Skip to content

Commit 20fa4ce

Browse files
authored
🔊 Add consistent errors for env vars not set (#200)
1 parent 1a64656 commit 20fa4ce

File tree

6 files changed

+80
-78
lines changed

6 files changed

+80
-78
lines changed

{{cookiecutter.project_slug}}/README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,10 @@ services:
489489
deploy:
490490
placement:
491491
constraints:
492-
- node.labels.${STACK_NAME}.app-db-data == true
492+
- node.labels.${STACK_NAME?Variable not set}.app-db-data == true
493493
```
494494

495-
note the `${STACK_NAME}`. In the script `./scripts/deploy.sh`, the `docker-compose.yml` would be converted, and saved to a file `docker-stack.yml` containing:
495+
note the `${STACK_NAME?Variable not set}`. In the script `./scripts/deploy.sh`, the `docker-compose.yml` would be converted, and saved to a file `docker-stack.yml` containing:
496496

497497
```yaml
498498
version: '3'
@@ -506,6 +506,8 @@ services:
506506
- node.labels.{{cookiecutter.docker_swarm_stack_name_main}}.app-db-data == true
507507
```
508508

509+
**Note**: The `${STACK_NAME?Variable not set}` means "use the environment variable `STACK_NAME`, but if it is not set, show an error `Variable not set`".
510+
509511
If you add more volumes to your stack, you need to make sure you add the corresponding constraints to the services that use that named volume.
510512

511513
Then you have to create those labels in some nodes in your Docker Swarm mode cluster. You can use `docker-auto-labels` to do it automatically.
@@ -632,10 +634,10 @@ You can do the process by hand based on those same scripts if you wanted. The ge
632634
```bash
633635
# Use the environment variables passed to this script, as TAG and FRONTEND_ENV
634636
# And re-create those variables as environment variables for the next command
635-
TAG=${TAG} \
637+
TAG=${TAG?Variable not set} \
636638
# Set the environment variable FRONTEND_ENV to the same value passed to this script with
637639
# a default value of "production" if nothing else was passed
638-
FRONTEND_ENV=${FRONTEND_ENV-production} \
640+
FRONTEND_ENV=${FRONTEND_ENV-production?Variable not set} \
639641
# The actual comand that does the work: docker-compose
640642
docker-compose \
641643
# Pass the file that should be used, setting explicitly docker-compose.yml avoids the
@@ -653,7 +655,7 @@ config > docker-stack.yml
653655
docker-auto-labels docker-stack.yml
654656
655657
# Now this command uses that same file to deploy it
656-
docker stack deploy -c docker-stack.yml --with-registry-auth "${STACK_NAME}"
658+
docker stack deploy -c docker-stack.yml --with-registry-auth "${STACK_NAME?Variable not set}"
657659
```
658660

659661
### Continuous Integration / Continuous Delivery

{{cookiecutter.project_slug}}/docker-compose.override.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ services:
1010
- --providers.docker
1111
# Add a constraint to only use services with the label for this stack
1212
# from the env var TRAEFIK_TAG
13-
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`, `${TRAEFIK_TAG}`)
13+
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`, `${TRAEFIK_TAG?Variable not set}`)
1414
# Do not expose all Docker services, only the ones explicitly exposed
1515
- --providers.docker.exposedbydefault=false
1616
# Disable Docker Swarm mode for local development
@@ -25,8 +25,8 @@ services:
2525
- --api.insecure=true
2626
labels:
2727
- traefik.enable=true
28-
- traefik.http.routers.${STACK_NAME}-traefik-public-http.rule=Host(`${DOMAIN}`)
29-
- traefik.http.services.${STACK_NAME}-traefik-public.loadbalancer.server.port=80
28+
- traefik.http.routers.${STACK_NAME?Variable not set}-traefik-public-http.rule=Host(`${DOMAIN?Variable not set}`)
29+
- traefik.http.services.${STACK_NAME?Variable not set}-traefik-public.loadbalancer.server.port=80
3030

3131
pgadmin:
3232
ports:
@@ -43,7 +43,7 @@ services:
4343
- ./backend/app:/app
4444
environment:
4545
- JUPYTER=jupyter lab --ip=0.0.0.0 --allow-root --NotebookApp.custom_display_url=http://127.0.0.1:8888
46-
- SERVER_HOST=http://${DOMAIN}
46+
- SERVER_HOST=http://${DOMAIN?Variable not set}
4747
build:
4848
context: ./backend
4949
dockerfile: backend.dockerfile
@@ -54,17 +54,17 @@ services:
5454
command: /start-reload.sh
5555
labels:
5656
- traefik.enable=true
57-
- traefik.constraint-label-stack=${TRAEFIK_TAG}
58-
- traefik.http.routers.${STACK_NAME}-backend-http.rule=PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`)
59-
- traefik.http.services.${STACK_NAME}-backend.loadbalancer.server.port=80
57+
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
58+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`)
59+
- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=80
6060

6161
celeryworker:
6262
volumes:
6363
- ./backend/app:/app
6464
environment:
6565
- RUN=celery worker -A app.worker -l info -Q main-queue -c 1
6666
- JUPYTER=jupyter lab --ip=0.0.0.0 --allow-root --NotebookApp.custom_display_url=http://127.0.0.1:8888
67-
- SERVER_HOST=http://${DOMAIN}
67+
- SERVER_HOST=http://${DOMAIN?Variable not set}
6868
build:
6969
context: ./backend
7070
dockerfile: celeryworker.dockerfile
@@ -79,9 +79,9 @@ services:
7979
FRONTEND_ENV: dev
8080
labels:
8181
- traefik.enable=true
82-
- traefik.constraint-label-stack=${TRAEFIK_TAG}
83-
- traefik.http.routers.${STACK_NAME}-frontend-http.rule=PathPrefix(`/`)
84-
- traefik.http.services.${STACK_NAME}-frontend.loadbalancer.server.port=80
82+
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
83+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.rule=PathPrefix(`/`)
84+
- traefik.http.services.${STACK_NAME?Variable not set}-frontend.loadbalancer.server.port=80
8585

8686
networks:
8787
traefik-public:

{{cookiecutter.project_slug}}/docker-compose.yml

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ services:
44
proxy:
55
image: traefik:v2.2
66
networks:
7-
- ${TRAEFIK_PUBLIC_NETWORK}
7+
- ${TRAEFIK_PUBLIC_NETWORK?Variable not set}
88
- default
99
volumes:
1010
- /var/run/docker.sock:/var/run/docker.sock
@@ -13,7 +13,7 @@ services:
1313
- --providers.docker
1414
# Add a constraint to only use services with the label for this stack
1515
# from the env var TRAEFIK_TAG
16-
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`, `${TRAEFIK_TAG}`)
16+
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`, `${TRAEFIK_TAG?Variable not set}`)
1717
# Do not expose all Docker services, only the ones explicitly exposed
1818
- --providers.docker.exposedbydefault=false
1919
# Enable Docker Swarm mode
@@ -32,41 +32,41 @@ services:
3232
# Enable Traefik for this service, to make it available in the public network
3333
- traefik.enable=true
3434
# Use the traefik-public network (declared below)
35-
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK}
35+
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK?Variable not set}
3636
# Use the custom label "traefik.constraint-label=traefik-public"
3737
# This public Traefik will only use services with this label
38-
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG}
38+
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG?Variable not set}
3939
# traefik-http set up only to use the middleware to redirect to https
40-
- traefik.http.middlewares.${STACK_NAME}-https-redirect.redirectscheme.scheme=https
41-
- traefik.http.middlewares.${STACK_NAME}-https-redirect.redirectscheme.permanent=true
40+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-https-redirect.redirectscheme.scheme=https
41+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-https-redirect.redirectscheme.permanent=true
4242
# Handle host with and without "www" to redirect to only one of them
4343
# Uses environment variable DOMAIN
4444
# To disable www redirection remove the Host() you want to discard, here and
4545
# below for HTTPS
46-
- traefik.http.routers.${STACK_NAME}-proxy-http.rule=Host(`${DOMAIN}`) || Host(`www.${DOMAIN}`)
47-
- traefik.http.routers.${STACK_NAME}-proxy-http.entrypoints=http
46+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-http.rule=Host(`${DOMAIN?Variable not set}`) || Host(`www.${DOMAIN?Variable not set}`)
47+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-http.entrypoints=http
4848
# traefik-https the actual router using HTTPS
49-
- traefik.http.routers.${STACK_NAME}-proxy-https.rule=Host(`${DOMAIN}`) || Host(`www.${DOMAIN}`)
50-
- traefik.http.routers.${STACK_NAME}-proxy-https.entrypoints=https
51-
- traefik.http.routers.${STACK_NAME}-proxy-https.tls=true
49+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-https.rule=Host(`${DOMAIN?Variable not set}`) || Host(`www.${DOMAIN?Variable not set}`)
50+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-https.entrypoints=https
51+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-https.tls=true
5252
# Use the "le" (Let's Encrypt) resolver created below
53-
- traefik.http.routers.${STACK_NAME}-proxy-https.tls.certresolver=le
53+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-https.tls.certresolver=le
5454
# Define the port inside of the Docker service to use
55-
- traefik.http.services.${STACK_NAME}-proxy.loadbalancer.server.port=80
55+
- traefik.http.services.${STACK_NAME?Variable not set}-proxy.loadbalancer.server.port=80
5656
# Handle domain with and without "www" to redirect to only one
5757
# To disable www redirection remove the next line
58-
- traefik.http.middlewares.${STACK_NAME}-www-redirect.redirectregex.regex=^https?://(www.)?(${DOMAIN})/(.*)
58+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.regex=^https?://(www.)?(${DOMAIN?Variable not set})/(.*)
5959
# Redirect a domain with www to non-www
6060
# To disable it remove the next line
61-
- traefik.http.middlewares.${STACK_NAME}-www-redirect.redirectregex.replacement=https://${DOMAIN}/$${3}
61+
- traefik.http.middlewares.${STACK_NAME?Variable not set}-www-redirect.redirectregex.replacement=https://${DOMAIN?Variable not set}/$${3}
6262
# Redirect a domain without www to www
6363
# To enable it remove the previous line and uncomment the next
6464
# - traefik.http.middlewares.${STACK_NAME}-www-redirect.redirectregex.replacement=https://www.${DOMAIN}/$${3}
6565
# Middleware to redirect www, to disable it remove the next line
66-
- traefik.http.routers.${STACK_NAME}-proxy-https.middlewares=${STACK_NAME}-www-redirect
66+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-https.middlewares=${STACK_NAME?Variable not set}-www-redirect
6767
# Middleware to redirect www, and redirect HTTP to HTTPS
68-
# to disable www redirection remove the section: ${STACK_NAME}-www-redirect,
69-
- traefik.http.routers.${STACK_NAME}-proxy-http.middlewares=${STACK_NAME}-www-redirect,${STACK_NAME}-https-redirect
68+
# to disable www redirection remove the section: ${STACK_NAME?Variable not set}-www-redirect,
69+
- traefik.http.routers.${STACK_NAME?Variable not set}-proxy-http.middlewares=${STACK_NAME?Variable not set}-www-redirect,${STACK_NAME?Variable not set}-https-redirect
7070

7171
db:
7272
image: postgres:12
@@ -79,12 +79,12 @@ services:
7979
deploy:
8080
placement:
8181
constraints:
82-
- node.labels.${STACK_NAME}.app-db-data == true
82+
- node.labels.${STACK_NAME?Variable not set}.app-db-data == true
8383

8484
pgadmin:
8585
image: dpage/pgadmin4
8686
networks:
87-
- ${TRAEFIK_PUBLIC_NETWORK}
87+
- ${TRAEFIK_PUBLIC_NETWORK?Variable not set}
8888
- default
8989
depends_on:
9090
- db
@@ -93,16 +93,16 @@ services:
9393
deploy:
9494
labels:
9595
- traefik.enable=true
96-
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK}
97-
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG}
98-
- traefik.http.routers.${STACK_NAME}-pgadmin-http.rule=Host(`pgadmin.${DOMAIN}`)
99-
- traefik.http.routers.${STACK_NAME}-pgadmin-http.entrypoints=http
100-
- traefik.http.routers.${STACK_NAME}-pgadmin-http.middlewares=${STACK_NAME}-https-redirect
101-
- traefik.http.routers.${STACK_NAME}-pgadmin-https.rule=Host(`pgadmin.${DOMAIN}`)
102-
- traefik.http.routers.${STACK_NAME}-pgadmin-https.entrypoints=https
103-
- traefik.http.routers.${STACK_NAME}-pgadmin-https.tls=true
104-
- traefik.http.routers.${STACK_NAME}-pgadmin-https.tls.certresolver=le
105-
- traefik.http.services.${STACK_NAME}-pgadmin.loadbalancer.server.port=5050
96+
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK?Variable not set}
97+
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG?Variable not set}
98+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.rule=Host(`pgadmin.${DOMAIN?Variable not set}`)
99+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.entrypoints=http
100+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-http.middlewares=${STACK_NAME?Variable not set}-https-redirect
101+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.rule=Host(`pgadmin.${DOMAIN?Variable not set}`)
102+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.entrypoints=https
103+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.tls=true
104+
- traefik.http.routers.${STACK_NAME?Variable not set}-pgadmin-https.tls.certresolver=le
105+
- traefik.http.services.${STACK_NAME?Variable not set}-pgadmin.loadbalancer.server.port=5050
106106

107107
queue:
108108
image: rabbitmq:3
@@ -114,7 +114,7 @@ services:
114114
flower:
115115
image: mher/flower
116116
networks:
117-
- ${TRAEFIK_PUBLIC_NETWORK}
117+
- ${TRAEFIK_PUBLIC_NETWORK?Variable not set}
118118
- default
119119
env_file:
120120
- .env
@@ -126,26 +126,26 @@ services:
126126
deploy:
127127
labels:
128128
- traefik.enable=true
129-
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK}
130-
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG}
131-
- traefik.http.routers.${STACK_NAME}-flower-http.rule=Host(`flower.${DOMAIN}`)
132-
- traefik.http.routers.${STACK_NAME}-flower-http.entrypoints=http
133-
- traefik.http.routers.${STACK_NAME}-flower-http.middlewares=${STACK_NAME}-https-redirect
134-
- traefik.http.routers.${STACK_NAME}-flower-https.rule=Host(`flower.${DOMAIN}`)
135-
- traefik.http.routers.${STACK_NAME}-flower-https.entrypoints=https
136-
- traefik.http.routers.${STACK_NAME}-flower-https.tls=true
137-
- traefik.http.routers.${STACK_NAME}-flower-https.tls.certresolver=le
138-
- traefik.http.services.${STACK_NAME}-flower.loadbalancer.server.port=5555
129+
- traefik.docker.network=${TRAEFIK_PUBLIC_NETWORK?Variable not set}
130+
- traefik.constraint-label=${TRAEFIK_PUBLIC_TAG?Variable not set}
131+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.rule=Host(`flower.${DOMAIN?Variable not set}`)
132+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.entrypoints=http
133+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-http.middlewares=${STACK_NAME?Variable not set}-https-redirect
134+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.rule=Host(`flower.${DOMAIN?Variable not set}`)
135+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.entrypoints=https
136+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.tls=true
137+
- traefik.http.routers.${STACK_NAME?Variable not set}-flower-https.tls.certresolver=le
138+
- traefik.http.services.${STACK_NAME?Variable not set}-flower.loadbalancer.server.port=5555
139139

140140
backend:
141-
image: '${DOCKER_IMAGE_BACKEND}:${TAG-latest}'
141+
image: '${DOCKER_IMAGE_BACKEND?Variable not set}:${TAG-latest}'
142142
depends_on:
143143
- db
144144
env_file:
145145
- .env
146146
environment:
147-
- SERVER_NAME=${DOMAIN}
148-
- SERVER_HOST=https://${DOMAIN}
147+
- SERVER_NAME=${DOMAIN?Variable not set}
148+
- SERVER_HOST=https://${DOMAIN?Variable not set}
149149
# Allow explicit env var override for tests
150150
- SMTP_HOST=${SMTP_HOST}
151151
build:
@@ -156,40 +156,40 @@ services:
156156
deploy:
157157
labels:
158158
- traefik.enable=true
159-
- traefik.constraint-label-stack=${TRAEFIK_TAG}
160-
- traefik.http.routers.${STACK_NAME}-backend-http.rule=PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`)
161-
- traefik.http.services.${STACK_NAME}-backend.loadbalancer.server.port=80
159+
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
160+
- traefik.http.routers.${STACK_NAME?Variable not set}-backend-http.rule=PathPrefix(`/api`) || PathPrefix(`/docs`) || PathPrefix(`/redoc`)
161+
- traefik.http.services.${STACK_NAME?Variable not set}-backend.loadbalancer.server.port=80
162162

163163
celeryworker:
164-
image: '${DOCKER_IMAGE_CELERYWORKER}:${TAG-latest}'
164+
image: '${DOCKER_IMAGE_CELERYWORKER?Variable not set}:${TAG-latest}'
165165
depends_on:
166166
- db
167167
- queue
168168
env_file:
169169
- .env
170170
environment:
171-
- SERVER_NAME=${DOMAIN}
172-
- SERVER_HOST=https://${DOMAIN}
171+
- SERVER_NAME=${DOMAIN?Variable not set}
172+
- SERVER_HOST=https://${DOMAIN?Variable not set}
173173
# Allow explicit env var override for tests
174-
- SMTP_HOST=${SMTP_HOST}
174+
- SMTP_HOST=${SMTP_HOST?Variable not set}
175175
build:
176176
context: ./backend
177177
dockerfile: celeryworker.dockerfile
178178
args:
179179
INSTALL_DEV: ${INSTALL_DEV-false}
180180

181181
frontend:
182-
image: '${DOCKER_IMAGE_FRONTEND}:${TAG-latest}'
182+
image: '${DOCKER_IMAGE_FRONTEND?Variable not set}:${TAG-latest}'
183183
build:
184184
context: ./frontend
185185
args:
186186
FRONTEND_ENV: ${FRONTEND_ENV-production}
187187
deploy:
188188
labels:
189189
- traefik.enable=true
190-
- traefik.constraint-label-stack=${TRAEFIK_TAG}
191-
- traefik.http.routers.${STACK_NAME}-frontend-http.rule=PathPrefix(`/`)
192-
- traefik.http.services.${STACK_NAME}-frontend.loadbalancer.server.port=80
190+
- traefik.constraint-label-stack=${TRAEFIK_TAG?Variable not set}
191+
- traefik.http.routers.${STACK_NAME?Variable not set}-frontend-http.rule=PathPrefix(`/`)
192+
- traefik.http.services.${STACK_NAME?Variable not set}-frontend.loadbalancer.server.port=80
193193

194194
volumes:
195195
app-db-data:

{{cookiecutter.project_slug}}/scripts/build-push.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Exit in case of error
44
set -e
55

6-
TAG=${TAG} \
6+
TAG=${TAG?Variable not set} \
77
FRONTEND_ENV=${FRONTEND_ENV-production} \
88
sh ./scripts/build.sh
99

{{cookiecutter.project_slug}}/scripts/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Exit in case of error
44
set -e
55

6-
TAG=${TAG} \
6+
TAG=${TAG?Variable not set} \
77
FRONTEND_ENV=${FRONTEND_ENV-production} \
88
docker-compose \
99
-f docker-compose.yml \

{{cookiecutter.project_slug}}/scripts/deploy.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
# Exit in case of error
44
set -e
55

6-
DOMAIN=${DOMAIN} \
7-
TRAEFIK_TAG=${TRAEFIK_TAG} \
8-
STACK_NAME=${STACK_NAME} \
9-
TAG=${TAG} \
6+
DOMAIN=${DOMAIN?Variable not set} \
7+
TRAEFIK_TAG=${TRAEFIK_TAG?Variable not set} \
8+
STACK_NAME=${STACK_NAME?Variable not set} \
9+
TAG=${TAG?Variable not set} \
1010
docker-compose \
1111
-f docker-compose.yml \
1212
config > docker-stack.yml
1313

1414
docker-auto-labels docker-stack.yml
1515

16-
docker stack deploy -c docker-stack.yml --with-registry-auth "${STACK_NAME}"
16+
docker stack deploy -c docker-stack.yml --with-registry-auth "${STACK_NAME?Variable not set}"

0 commit comments

Comments
 (0)