You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
@@ -44,11 +44,37 @@ When you select Python in the menu:
44
44
- iotstack_nw
45
45
```
46
46
47
-
Notes:
47
+
Note:
48
48
49
49
* This service definition is for "new menu" (master branch). The only difference with "old menu" (old-menu branch) is the omission of the last two lines.
50
-
* See also [customising your Python service definition](#customisingPython).
51
50
51
+
### <aname="customisingPython"> customising your Python service definition </a>
52
+
53
+
The service definition contains a number of customisation points:
54
+
55
+
1.`restart: unless-stopped` assumes your Python script will run in an infinite loop. If your script is intended to run once and terminate, you should remove this directive.
56
+
2.`TZ=Etc/UTC` should be set to your local time-zone. Never use quote marks on the right hand side of a `TZ=` variable.
57
+
3. If you are running as a different user ID, you may want to change both `IOTSTACK_UID` and `IOTSTACK_GID` to appropriate values.
58
+
59
+
Notes:
60
+
61
+
* Don't use user and group *names* because these variables are applied *inside* the container where those names are (probably) undefined.
62
+
* The only thing these variables affect is the ownership of:
63
+
64
+
```
65
+
~/IOTstack/volumes/python/app
66
+
```
67
+
68
+
and its contents. If you want everything to be owned by root, set both of these variables to zero (eg `IOTSTACK_UID=0`).
69
+
70
+
4. If your Python script listens to data-communications traffic, you can set up the port mappings by uncommenting the `ports:` directive.
71
+
72
+
If your Python container is already running when you make a change to its service definition, you can apply it via:
73
+
74
+
```bash
75
+
$ cd~/IOTstack
76
+
$ docker-compose up -d python
77
+
```
52
78
53
79
## <aname="firstLaunchPython"> Python - first launch </a>
54
80
@@ -163,21 +189,6 @@ Each time you launch the Python container *after* the first launch:
163
189
2. The `docker-entrypoint.sh` script runs and performs "self-repair" by replacing any files that have gone missing from the persistent storage area. Self-repair does **not** overwrite existing files!
164
190
3. The `app.py` Python script is run.
165
191
166
-
## <aname="yourPythonScript"> developing your own Python script </a>
167
-
168
-
1. Edit (or replace) the file:
169
-
170
-
```
171
-
~/IOTstack/volumes/python/app/app.py
172
-
```
173
-
174
-
2. Tell the python container to notice the change by:
175
-
176
-
```bash
177
-
$ cd ~/IOTstack
178
-
$ docker-compose restart python
179
-
```
180
-
181
192
## <aname="debugging"> when things go wrong - check the log </a>
182
193
183
194
If the container misbehaves, the log is your friend:
@@ -186,9 +197,67 @@ If the container misbehaves, the log is your friend:
186
197
$ docker logs python
187
198
```
188
199
189
-
## <aname="cleanSlate"> getting a clean slate </a>
200
+
## <aname="yourPythonScript"> project development life-cycle </a>
201
+
202
+
It is **critical** that you understand that **all** of your project development should occur within the folder:
203
+
204
+
```
205
+
~/IOTstack/volumes/python/app
206
+
```
207
+
208
+
So long as you are performing some sort of routine backup (either with a supplied script or a third party solution like [Paraphraser/IOTstackBackup](https://github.com/Paraphraser/IOTstackBackup)), your work will be protected.
190
209
191
-
If you make a mess of things and need to start from a clean slate:
210
+
### <aname="gettingStarted"> getting started </a>
211
+
212
+
Start by editing the file:
213
+
214
+
```
215
+
~/IOTstack/volumes/python/app/app.py
216
+
```
217
+
218
+
If you need other supporting scripts or data files, also add those to the directory:
219
+
220
+
```
221
+
~/IOTstack/volumes/python/app
222
+
```
223
+
224
+
Any time you change something in the `app` folder, tell the running python container to notice the change by:
225
+
226
+
```bash
227
+
$ cd~/IOTstack
228
+
$ docker-compose restart python
229
+
```
230
+
231
+
### <aname="persistentStorage"> reading and writing to disk </a>
232
+
233
+
Consider this line in the service definition:
234
+
235
+
```
236
+
- ./volumes/python/app:/usr/src/app
237
+
```
238
+
239
+
The leading period means "the directory containing `docker-compose.yml`" so it the same as:
240
+
241
+
```
242
+
- ~/IOTstack/volumes/python/app:/usr/src/app
243
+
```
244
+
245
+
Then, you split the line at the ":", resulting in:
246
+
247
+
* The *external* directory = `~/IOTstack/volumes/python/app`
248
+
* The *internal* directory = `/usr/src/app`
249
+
250
+
What it means is that:
251
+
252
+
* Any file you put into the *external* directory (or any sub-directories you create within the *external* directory) will be visible to your Python script running inside the container at the same relative position in the *internal* directory.
253
+
* Any file or sub-directory created in the *internal* directory by your Python script running inside the container will be visible outside the container at the same relative position in the *external* directory.
254
+
* The contents of *external* directory and, therefore, the *internal* directory will persist across container launches.
255
+
256
+
If your script writes into any other directory inside the container, the data will be lost when the container re-launches.
257
+
258
+
### <aname="cleanSlate"> getting a clean slate </a>
259
+
260
+
If you make a mess of things and need to start from a clean slate, erase the persistent storage area:
192
261
193
262
```bash
194
263
$ cd~/IOTstack
@@ -199,23 +268,101 @@ $ docker-compose up -d python
199
268
200
269
The container will re-initialise the persistent storage area from its defaults.
201
270
202
-
## <aname="bakingPython"> making your own Python script the default </a>
271
+
### <aname="addingPackages"> adding packages </a>
272
+
273
+
As you develop your project, you may find that you need to add supporting packages. For this example, we will assume you want to add "[Flask](https://pypi.org/project/Flask/)" and "[beautifulsoup4](https://pypi.org/project/beautifulsoup4/)".
203
274
204
-
Suppose you have been developing a Python script and you want to "freeze dry" everything into an image so that it becomes the default when you ask for a clean slate.
275
+
If you were developing a project outside of container-space, you would simply run:
205
276
206
-
1. If you have identified a need for a `requirements.txt`, create that by running the following command:
277
+
```
278
+
$ pip3 install -U Flask beautifulsoup4
279
+
```
280
+
281
+
You *can* do the same thing with the running container:
5. Continue your development work by returning to [getting started](#gettingStarted).
326
+
327
+
Note:
328
+
329
+
* The first time you following the process described above to create `requirements.txt`, a copy will appear at:
330
+
331
+
```
332
+
~/IOTstack/volumes/python/app/requirements.txt
333
+
```
334
+
335
+
This copy is the result of the "self-repair" code that runs each time the container starts noticing that `requirements.txt` is missing and making a copy from the defaults stored inside the image.
336
+
337
+
If you make more changes to the master version of `requirements.txt` in the *services* directory and rebuild the local image, the copy in the *volumes* directory will **not** be kept in-sync. That's because the "self-repair" code **never** overwrites existing files.
338
+
339
+
If you want to bring the copy of `requirements.txt` in the *volumes* directory up-to-date:
340
+
341
+
```
342
+
$ cd ~/IOTstack
343
+
$ rm ./volumes/python/app/requirements.txt
344
+
$ docker-compose restart python
345
+
```
346
+
347
+
The `requirements.txt` file will be recreated and it will be a copy of the version in the *services* directory as of the last image rebuild.
348
+
349
+
### <aname="scriptBaking"> making your own Python script the default </a>
350
+
351
+
Suppose the Python script you have been developing reaches a major milestone and you decide to "freeze dry" your work up to that point so that it becomes the default when you ask for a [clean slate](#cleanSlate). Proceed like this:
352
+
353
+
1. If you have added any packages by following the steps in [adding packages](#addingPackages), run the following command:
That creates a file at the following path (it will be owned by root):
359
+
That generates a `requirements.txt` representing the state of play inside the running container. Because it is running *inside* the container, the `requirements.txt` created by that command appears *outside* the container at:
213
360
214
361
```
215
362
~/IOTstack/volumes/python/app/requirements.txt
216
363
```
217
-
218
-
2.Run the following commands:
364
+
365
+
2.Make your work the default:
219
366
220
367
```bash
221
368
$ cd ~/IOTstack
@@ -225,12 +372,12 @@ Suppose you have been developing a Python script and you want to "freeze dry" ev
225
372
The `cp` command copies:
226
373
227
374
* your Python script;
228
-
* the optional `requirements.txt`; and
375
+
* the optional `requirements.txt` (from step 1); and
229
376
* any other files you may have put into the Python working directory.
230
377
231
378
Key point:
232
379
233
-
* **everything** copied into the `./services/python/app` directory will become part of the new image.
380
+
* **everything** copied into `./services/python/app` will become part of the new local image.
234
381
235
382
3. Terminate the Python container and erase its persistent storage area:
236
383
@@ -252,53 +399,85 @@ Suppose you have been developing a Python script and you want to "freeze dry" ev
252
399
4. Rebuild the local image:
253
400
254
401
```bash
255
-
$ cd ~IOTstack
256
-
$ docker-compose up --build -d python
402
+
$ cd ~/IOTstack
403
+
$ docker-compose build --force-rm python
404
+
$ docker-compose up -d --force-recreate python
257
405
```
258
-
259
-
The `--build` directive will trigger a new Dockerfile run which, in turn, will process the (optional) `requirements.txt` and then bundle your Python application and any other supporting folders and files into a new local image, and then instantiate that to be the new running container.
260
-
261
-
On its first launch, the new container will re-populate the persistent storage area but, this time it will be your Python script and any other supporting files, rather than the original "hello world" script.
406
+
407
+
On its first launch, the new container will re-populate the persistent storage area but, this time, it will be your Python script and any other supporting files, rather than the original "hello world" script.
262
408
263
409
5. Clean up by removing the old local image:
264
410
265
411
```bash
266
412
$ docker system prune -f
267
413
```
268
414
269
-
## <aname="customisingPython"> customising your Python service definition </a>
415
+
###<aname="scriptCanning"> canning your project </a>
270
416
271
-
The service definition shown in [selecting Python in the menu](#menuPython) contains a number of customisation points:
417
+
Suppose your project has reached the stage where you wish to put it into production as a service under its own name. Make two further assumptions:
272
418
273
-
1.`restart: unless-stopped` assumes your Python script will run in an infinite loop. If your script is intended to run once and terminate, you should remove this directive.
274
-
2.`TZ=Etc/UTC` should be set to your local time-zone. Never use quote marks on the right hand side of a `TZ=` variable.
275
-
3. If you are running as a different user ID, you may want to change both `IOTSTACK_UID` and `IOTSTACK_GID` to appropriate values.
419
+
1. You have gone through the steps in [making your own Python script the default](#scriptBaking) and you are **certain** that the content of `./services/python/app` correctly captures your project.
420
+
2. You want to give your project the name "wishbone".
276
421
277
-
Notes:
422
+
Proceed like this:
278
423
279
-
* Don't use user and group *names* because these variables are applied *inside* the container where those names are (probably) undefined.
280
-
* The only thing these variables affect is the ownership of:
424
+
1. Stop the development project:
281
425
282
-
```
283
-
~/IOTstack/volumes/python/app
284
-
```
426
+
```
427
+
$ cd ~/IOTstack
428
+
$ docker-compose rm --force --stop -v python
429
+
```
285
430
286
-
and its contents. If you want everything to be owned by root, set both of these variables to zero (eg `IOTSTACK_UID=0`).
431
+
2. Remove the existing local image:
287
432
288
-
4. If your Python script listens to data-communications traffic, you can set up the port mappings by uncommenting the `ports:` directive.
433
+
```
434
+
$ docker rmi iotstack_python
435
+
```
436
+
437
+
3. Rename the `python` services directory to the name of your project:
289
438
290
-
After making a change to the service definition, you can apply it via:
439
+
```
440
+
$ cd ~/IOTstack/services
441
+
$ mv python wishbone
442
+
```
291
443
292
-
```bash
293
-
$ cd~/IOTstack
294
-
$ docker-compose up -d python
295
-
```
444
+
4. Edit the `python` service definition in `docker-compose.yml` and replace references to `python` with the name of your project. In the following, the original is on the left, the edited version on the right, and the lines that need to change are indicated with a "|":
* if you make a copy of the `python` service definition and then perform the required "wishbone" edits on the copy, the `python` definition will still be active so `docker-compose` may try to bring up both services. You will eliminate the risk of confusing yourself if you follow these instructions "as written" by **not** leaving the `python` service definition in place.
466
+
467
+
5. Start the renamed service:
468
+
469
+
```
470
+
$ cd ~/IOTstack
471
+
$ docker-compose up -d wishbone
472
+
```
296
473
297
-
## <aname="persistentStorage"> writing to disk </a>
474
+
Remember:
298
475
299
-
Inside the container the working directory is `/usr/src/app` (ie as mapped in the `volumes:` directive of the service definition). Any data your Python script writes into this directory (or a sub-directory) will persist across container launches.
476
+
* After you have done this, the persistent storage area will be at the path:
300
477
301
-
If your script writes into any other directory inside the container, the data will be lost when the container re-launches.
The old base image can't be removed until the old local image has been removed, which is why the `prune` command needs to be run twice.
502
+
The old base image can't be removed until the old local image has been removed, which is why the `prune` command needs to be run twice.
503
+
504
+
Note:
505
+
506
+
* If you have followed the steps in [canning your project](#scriptCanning) and your service has a name other than `python`, just substitute the new name where you see `python` in the two `dockerc-compose` commands.
0 commit comments