Skip to content

Commit 7f25edf

Browse files
mrnicegyu11kaisersanderegg
authored
♻️ Migrate to docker stack config (ITISFoundation#5523)
Co-authored-by: kaiser <[email protected]> Co-authored-by: Sylvain <[email protected]>
1 parent 3afe0b9 commit 7f25edf

File tree

17 files changed

+149
-272
lines changed

17 files changed

+149
-272
lines changed

.env-devel

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ AUTOSCALING_EC2_ACCESS=null
2525
AUTOSCALING_EC2_INSTANCES=null
2626
AUTOSCALING_NODES_MONITORING=null
2727
AUTOSCALING_POLL_INTERVAL=10
28+
AUTOSCALING_LOGLEVEL=INFO
2829

2930

3031
BF_API_KEY=none
@@ -43,19 +44,21 @@ CLUSTERS_KEEPER_PRIMARY_EC2_INSTANCES=null
4344
CLUSTERS_KEEPER_TASK_INTERVAL=30
4445
CLUSTERS_KEEPER_WORKERS_EC2_INSTANCES=null
4546
CLUSTERS_KEEPER_EC2_INSTANCES_PREFIX=""
46-
47+
CLUSTERS_KEEPER_LOGLEVEL=INFO
4748

4849
DASK_SCHEDULER_HOST=dask-scheduler
4950
DASK_SCHEDULER_PORT=8786
5051
DASK_TLS_CA_FILE=/home/scu/.dask/dask-crt.pem
5152
DASK_TLS_KEY=/home/scu/.dask/dask-key.pem
5253
DASK_TLS_CERT=/home/scu/.dask/dask-crt.pem
54+
CLUSTERS_KEEPER_COMPUTATIONAL_BACKEND_DEFAULT_CLUSTER_AUTH='{"type":"tls","tls_ca_file":"/home/scu/.dask/dask-crt.pem","tls_client_cert":"/home/scu/.dask/dask-crt.pem","tls_client_key":"/home/scu/.dask/dask-key.pem"}'
5355

5456
DIRECTOR_REGISTRY_CACHING_TTL=900
5557
DIRECTOR_REGISTRY_CACHING=True
5658
DIRECTOR_GENERIC_RESOURCE_PLACEMENT_CONSTRAINTS_SUBSTITUTIONS='{}'
5759

5860
COMPUTATIONAL_BACKEND_DEFAULT_CLUSTER_URL=tls://dask-scheduler:8786
61+
COMPUTATIONAL_BACKEND_DEFAULT_CLUSTER_AUTH='{"type":"tls","tls_ca_file":"/home/scu/.dask/dask-crt.pem","tls_client_cert":"/home/scu/.dask/dask-crt.pem","tls_client_key":"/home/scu/.dask/dask-key.pem"}'
5962
COMPUTATIONAL_BACKEND_DEFAULT_CLUSTER_FILE_LINK_TYPE=S3
6063
COMPUTATIONAL_BACKEND_DEFAULT_FILE_LINK_TYPE=PRESIGNED
6164
COMPUTATIONAL_BACKEND_ON_DEMAND_CLUSTERS_FILE_LINK_TYPE=PRESIGNED
@@ -142,12 +145,6 @@ S3_ENDPOINT=172.17.0.1:9001
142145
S3_SECRET_KEY=12345678
143146
S3_SECURE=0
144147

145-
S3_EXPORT_ACCESS_KEY=87654321
146-
S3_EXPORT_BUCKET_NAME=simcore-export
147-
S3_EXPORT_ENDPOINT=172.17.0.1:9001
148-
S3_EXPORT_SECRET_KEY=87654321
149-
S3_EXPORT_SECURE=0
150-
151148
SCICRUNCH_API_BASE_URL=https://scicrunch.org/api/1
152149
SCICRUNCH_API_KEY=REPLACE_ME_with_valid_api_key
153150

.pre-commit-config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,10 @@ repos:
5252
language: script
5353
types: [file, python]
5454
entry: scripts/precommit/pytest-testit.bash
55+
- repo: local
56+
hooks:
57+
- id: validate-docker-compose
58+
name: validate-docker-compose
59+
language: script
60+
types: [file]
61+
entry: scripts/precommit/validate-docker-compose.bash

Makefile

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ CPU_COUNT = $(shell cat /proc/cpuinfo | grep processor | wc -l )
238238
@export DOCKER_REGISTRY=local && \
239239
export DOCKER_IMAGE_TAG=development && \
240240
export DEV_PC_CPU_COUNT=${CPU_COUNT} && \
241-
scripts/docker/docker-compose-config.bash -e .env \
241+
scripts/docker/docker-stack-config.bash -e .env \
242242
services/docker-compose.yml \
243243
services/docker-compose.local.yml \
244244
services/docker-compose.devel.yml \
@@ -248,7 +248,7 @@ CPU_COUNT = $(shell cat /proc/cpuinfo | grep processor | wc -l )
248248
# Creating config for stack with 'local/{service}:production' to $@
249249
@export DOCKER_REGISTRY=local && \
250250
export DOCKER_IMAGE_TAG=production && \
251-
scripts/docker/docker-compose-config.bash -e .env \
251+
scripts/docker/docker-stack-config.bash -e .env \
252252
services/docker-compose.yml \
253253
services/docker-compose.local.yml \
254254
> $@
@@ -258,15 +258,15 @@ CPU_COUNT = $(shell cat /proc/cpuinfo | grep processor | wc -l )
258258
# Creating config for stack with 'local/{service}:production' (except of static-webserver -> static-webserver:development) to $@
259259
@export DOCKER_REGISTRY=local && \
260260
export DOCKER_IMAGE_TAG=production && \
261-
scripts/docker/docker-compose-config.bash -e $< \
261+
scripts/docker/docker-stack-config.bash -e $< \
262262
services/docker-compose.yml \
263263
services/docker-compose.local.yml \
264264
services/docker-compose.devel-frontend.yml \
265265
> $@
266266

267267
.stack-simcore-version.yml: .env $(docker-compose-configs)
268268
# Creating config for stack with '$(DOCKER_REGISTRY)/{service}:${DOCKER_IMAGE_TAG}' to $@
269-
@scripts/docker/docker-compose-config.bash -e .env \
269+
@scripts/docker/docker-stack-config.bash -e .env \
270270
services/docker-compose.yml \
271271
services/docker-compose.local.yml \
272272
> $@
@@ -276,13 +276,13 @@ CPU_COUNT = $(shell cat /proc/cpuinfo | grep processor | wc -l )
276276
# Creating config for ops stack to $@
277277
ifdef ops_ci
278278
@$(shell \
279-
scripts/docker/docker-compose-config.bash -e .env \
279+
scripts/docker/docker-stack-config.bash -e .env \
280280
services/docker-compose-ops-ci.yml \
281281
> $@ \
282282
)
283283
else
284284
@$(shell \
285-
scripts/docker/docker-compose-config.bash -e .env \
285+
scripts/docker/docker-stack-config.bash -e .env \
286286
services/docker-compose-ops.yml \
287287
> $@ \
288288
)

packages/pytest-simcore/src/pytest_simcore/docker_compose.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,19 @@ def env_file_for_testing(
101101
# https://docs.docker.com/compose/environment-variables/#the-env-file
102102

103103
env_test_path = temp_folder / ".env.test"
104-
105104
with env_test_path.open("wt") as fh:
106105
print(
107106
f"# Auto-generated from env_file_for_testing in {__file__}",
108107
file=fh,
109108
)
110-
for key in sorted(testing_environ_vars.keys()):
111-
print(f"{key}={testing_environ_vars[key]}", file=fh)
109+
for key, value in sorted(testing_environ_vars.items()):
110+
# NOTE: python-dotenv parses JSON encoded strings correctly, but
111+
# writing them back shows an issue. if the original ENV is something like MY_ENV='{"correct": "encodedjson"}'
112+
# it goes to MY_ENV={"incorrect": "encodedjson"}!
113+
if value.startswith(("{", "[")) and value.endswith(("}", "]")):
114+
print(f"{key}='{value}'", file=fh)
115+
else:
116+
print(f"{key}={value}", file=fh)
112117

113118
#
114119
# WARNING: since compose files have references to ../.env we MUST create .env

packages/pytest-simcore/src/pytest_simcore/helpers/utils_docker.py

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,8 @@ def run_docker_compose_config(
140140
".yaml",
141141
], "Expected yaml/yml file as destination path"
142142

143-
# SEE https://docs.docker.com/compose/reference/
144-
bash_options = [
145-
"-p",
146-
str(project_dir), # Specify an alternate working directory
147-
]
148143
# https://docs.docker.com/compose/environment-variables/#using-the---env-file--option
149-
bash_options += [
144+
bash_options = [
150145
"-e",
151146
str(env_file_path), # Custom environment variables
152147
]
@@ -158,15 +153,13 @@ def run_docker_compose_config(
158153
bash_options += [os.path.relpath(docker_compose_path, project_dir)]
159154

160155
# SEE https://docs.docker.com/compose/reference/config/
161-
docker_compose_path = scripts_dir / "docker" / "docker-compose-config.bash"
156+
docker_compose_path = scripts_dir / "docker" / "docker-stack-config.bash"
162157
assert docker_compose_path.exists()
163-
164158
args = [f"{docker_compose_path}", *bash_options]
165159
print(" ".join(args))
166160

167161
process = subprocess.run(
168162
args,
169-
shell=False,
170163
cwd=project_dir,
171164
capture_output=True,
172165
check=True,
@@ -176,20 +169,6 @@ def run_docker_compose_config(
176169
compose_file_str = process.stdout.decode("utf-8")
177170
compose_file: dict[str, Any] = yaml.safe_load(compose_file_str)
178171

179-
def _remove_top_level_name_attribute_generated_by_compose_v2(
180-
compose: dict[str, Any]
181-
) -> dict[str, Any]:
182-
"""docker compose V2 CLI config adds a top level name attribute
183-
https://docs.docker.com/compose/compose-file/#name-top-level-element
184-
but it is incompatible with docker stack deploy...
185-
"""
186-
compose.pop("name", None)
187-
return compose
188-
189-
compose_file = _remove_top_level_name_attribute_generated_by_compose_v2(
190-
compose_file
191-
)
192-
193172
if destination_path:
194173
#
195174
# NOTE: This step could be avoided and reading instead from stdout
@@ -282,7 +261,7 @@ def save_docker_infos(destination_dir: Path):
282261
json.dumps(container.attrs, indent=2)
283262
)
284263

285-
except Exception as err: # pylint: disable=broad-except
264+
except Exception as err: # pylint: disable=broad-except # noqa: PERF203
286265
if container.status != ContainerStatus.created:
287266
print(
288267
f"Error while dumping {container.name=}, {container.status=}.\n\t{err=}"

scripts/docker/docker-compose-config.bash

Lines changed: 0 additions & 115 deletions
This file was deleted.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/bin/bash
2+
# generated using chatgpt
3+
show_info() {
4+
local message="$1"
5+
echo -e "\e[37mInfo:\e[0m $message" >&2
6+
}
7+
8+
show_warning() {
9+
local message="$1"
10+
echo -e "\e[31mWarning:\e[0m $message" >&2
11+
}
12+
13+
show_error() {
14+
local message="$1"
15+
echo -e "\e[31mError:\e[0m $message" >&2
16+
}
17+
18+
env_file=".env"
19+
# Parse command line arguments
20+
while getopts ":e:" opt; do
21+
case $opt in
22+
e)
23+
env_file="$OPTARG"
24+
;;
25+
\?)
26+
show_error "Invalid option: -$OPTARG"
27+
exit 1
28+
;;
29+
:)
30+
show_error "Option -$OPTARG requires an argument."
31+
exit 1
32+
;;
33+
esac
34+
done
35+
shift $((OPTIND - 1))
36+
37+
if [[ "$#" -eq 0 ]]; then
38+
show_error "No compose files specified!"
39+
exit 1
40+
fi
41+
42+
# Check if Docker version is greater than or equal to 24.0.9
43+
version_check=$(docker --version | grep --extended-regexp --only-matching '[0-9]+\.[0-9]+\.[0-9]+')
44+
IFS='.' read -r -a version_parts <<<"$version_check"
45+
46+
if [[ "${version_parts[0]}" -gt 24 ]] ||
47+
{ [[ "${version_parts[0]}" -eq 24 ]] && [[ "${version_parts[1]}" -gt 0 ]]; } ||
48+
{ [[ "${version_parts[0]}" -eq 24 ]] && [[ "${version_parts[1]}" -eq 0 ]] && [[ "${version_parts[2]}" -ge 9 ]]; }; then
49+
show_info "Running Docker version $version_check"
50+
else
51+
show_error "Docker version 25.0.3 or higher is required."
52+
exit 1
53+
fi
54+
55+
# shellcheck disable=SC2002
56+
docker_command="\
57+
set -o allexport && \
58+
. ${env_file} && set +o allexport && \
59+
docker stack config"
60+
61+
for compose_file_path in "$@"; do
62+
docker_command+=" --compose-file ${compose_file_path}"
63+
done
64+
# WE CANNOT DO THIS:
65+
# docker_command+=" --skip-interpolation"
66+
# because docker stack compose will *validate* that e.g. `replicas: ${SIMCORE_SERVICES_POSTGRES_REPLICAS}` is a valid number, which it is not if it is read as a literal string.
67+
68+
# Execute the command
69+
show_info "Executing Docker command: ${docker_command}"
70+
eval "${docker_command}"

0 commit comments

Comments
 (0)