-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
214 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
# cronjob | ||
|
||
Use [*swarm-cronjob*](https://github.com/crazy-max/swarm-cronjob) to launch *gantry* at a given time. | ||
Use [*swarm-cronjob*](https://github.com/crazy-max/swarm-cronjob) to launch [*Gantry*](https://github.com/shizunge/gantry) at a specific time. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# webhook | ||
|
||
This example describes how to launch [*Gantry*](https://github.com/shizunge/gantry) via [adnanh/webhook](https://github.com/adnanh/webhook). | ||
|
||
## Setup | ||
|
||
We leverage a dockerized webhook image [lwlook/webhook](https://hub.docker.com/r/lwlook/webhook) which is based on the offical Docker image. This allows us to launch the *Gantry* service with simple docker commands. | ||
|
||
[hooks.json](./hooks.json) defines the webhook's behavior. It parses incoming payloads and transforms them into environment variables like `GANTRY_SERVICES_EXCLUDED`, `GANTRY_SERVICES_EXCLUDED_FILTERS` and `GANTRY_SERVICES_FILTERS`. These variables are then used by [run_gantry.sh](./run_gantry.sh) to control *Gantry* behaviors. which means you can update different services by passing different payloads to the webhook. Refer to the [adnanh/webhook](https://github.com/adnanh/webhook) repository for more advanced webhook configurations, including securing the webhook with `trigger-rule`. | ||
|
||
[run_gantry.sh](./run_gantry.sh) is responsible for launching the *Gantry* service. | ||
|
||
## Test | ||
|
||
Use the following command to deploy the Docker Compose stack that includes the webhook service. | ||
|
||
``` | ||
docker stack deploy --detach=true --prune --with-registry-auth --compose-file ./docker-compose.yml webhook | ||
``` | ||
|
||
Use curl to send a POST request to the webhook endpoint. This request tells the *Gantry* to only update the service named "webhook_webhook". | ||
|
||
``` | ||
curl -X POST localhost:9000/hooks/run-gantry -H "Content-Type: application/json" -d '{"GANTRY_SERVICES_FILTERS":"name=webhook_webhook"}' | ||
``` | ||
|
||
Check the webhook service logs to confirm if the webhook was triggered correctly. | ||
|
||
``` | ||
docker service logs webhook_webhook | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
version: "3.8" | ||
|
||
services: | ||
webhook: | ||
image: lwlook/webhook:latest | ||
command: | ||
- -verbose | ||
- -hooks=/hooks.json | ||
- -hotreload | ||
ports: | ||
- "9000:9000" | ||
configs: | ||
- source: hooks_json | ||
target: /hooks.json | ||
- source: run_gantry | ||
target: /run_gantry.sh | ||
mode: 0550 | ||
volumes: | ||
- /var/run/docker.sock:/var/run/docker.sock | ||
deploy: | ||
placement: | ||
constraints: | ||
- node.role==manager | ||
|
||
# Note: run_gantry.sh does not use this service by default. | ||
# This service is left here to demonstrate a potential approach for reusing the same service | ||
# by scaling its replicas instead of starting a new service each webhook request. | ||
# See function resume_gantry in run_gantry.sh. | ||
# Pros: | ||
# * This approach can work together with other launching methods like crazymax/swarm-cronjob. | ||
# Cons: | ||
# * Concurrency Issues: Sending webhook requests too frequently can increase the chance of the | ||
# webhook failing to launch Gantry correctly for some requests due to the existing service | ||
# potentially handling a previous command. | ||
gantry: | ||
image: shizunge/gantry:latest | ||
volumes: | ||
- /var/run/docker.sock:/var/run/docker.sock | ||
environment: | ||
- "GANTRY_NODE_NAME={{.Node.Hostname}}" | ||
- "GANTRY_SLEEP_SECONDS=0" | ||
deploy: | ||
replicas: 0 | ||
placement: | ||
constraints: | ||
- node.role==manager | ||
restart_policy: | ||
condition: none | ||
labels: | ||
# The label can be used to find this service. | ||
# This can be used together with resume_gantry function in the run_gantry.sh | ||
- webhook.run-gantry=true | ||
|
||
configs: | ||
hooks_json: | ||
name: hooks_json | ||
file: ./hooks.json | ||
run_gantry: | ||
name: run_gantry | ||
file: ./run_gantry.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[ | ||
{ | ||
"id": "run-gantry", | ||
"execute-command": "/run_gantry.sh", | ||
"command-working-directory": "/", | ||
"pass-environment-to-command": | ||
[ | ||
{ | ||
"source": "payload", | ||
"name": "GANTRY_SERVICES_EXCLUDED", | ||
"envname": "GANTRY_SERVICES_EXCLUDED" | ||
}, | ||
{ | ||
"source": "payload", | ||
"name": "GANTRY_SERVICES_EXCLUDED_FILTERS", | ||
"envname": "GANTRY_SERVICES_EXCLUDED_FILTERS" | ||
}, | ||
{ | ||
"source": "payload", | ||
"name": "GANTRY_SERVICES_FILTERS", | ||
"envname": "GANTRY_SERVICES_FILTERS" | ||
} | ||
] | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
#!/bin/sh | ||
# Copyright (C) 2024 Shizun Ge | ||
# | ||
# This program is free software: you can redistribute it and/or modify | ||
# it under the terms of the GNU General Public License as published by | ||
# the Free Software Foundation, either version 3 of the License, or | ||
# (at your option) any later version. | ||
# | ||
# This program is distributed in the hope that it will be useful, | ||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
# GNU General Public License for more details. | ||
# | ||
# You should have received a copy of the GNU General Public License | ||
# along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
# | ||
|
||
_docker_start_replicated_job() { | ||
local ARGS="${@}" | ||
if [ -z "${ARGS}" ]; then | ||
echo "No services set." | ||
echo "Services that are not running:" | ||
docker service ls | grep "0/" | ||
return 0 | ||
fi | ||
for S in ${ARGS}; do | ||
echo -n "Set replicas to 0 to ${S}: " | ||
docker service update --replicas=0 "${S}" | ||
echo -n "Set replicas to 1 to ${S}: " | ||
docker service update --detach --replicas=1 "${S}" | ||
done | ||
} | ||
|
||
_get_number_of_running_tasks() { | ||
local FILTER="${1}" | ||
local REPLICAS= | ||
if ! REPLICAS=$(docker service ls --filter "${FILTER}" --format '{{.Replicas}}' | head -n 1); then | ||
return 1 | ||
fi | ||
# https://docs.docker.com/engine/reference/commandline/service_ls/#examples | ||
# The REPLICAS is like "5/5" or "1/1 (3/5 completed)" | ||
# Get the number before the first "/". | ||
local NUM_RUNS= | ||
NUM_RUNS=$(echo "${REPLICAS}/" | cut -d '/' -f 1) | ||
echo "${NUM_RUNS}" | ||
} | ||
|
||
resume_gantry() { | ||
local FILTER="label=webhook.run-gantry=true" | ||
local SERVICE_NAME=$(docker service ls --filter "${FILTER}" --format "{{.Name}}" | head -n 1) | ||
if [ -z "${SERVICE_NAME}" ]; then | ||
echo "Cannot find a service from ${FILTER}." | ||
return 1 | ||
fi | ||
local replicas= | ||
if ! replicas=$(_get_number_of_running_tasks "${FILTER}"); then | ||
echo "Failed to obtain task states of service from ${FILTER}." | ||
return 1 | ||
fi | ||
if [ "${replicas}" != "0" ]; then | ||
echo "${SERVICE_NAME} is still running. There are ${replicas} running tasks." | ||
return 1 | ||
fi | ||
docker service update --detach --env-add "GANTRY_SERVICES_EXCLUDED=${GANTRY_SERVICES_EXCLUDED}" "${SERVICE_NAME}" | ||
docker service update --detach --env-add "GANTRY_SERVICES_EXCLUDED_FILTERS=${GANTRY_SERVICES_EXCLUDED_FILTERS}" "${SERVICE_NAME}" | ||
docker service update --detach --env-add "GANTRY_SERVICES_FILTERS=${GANTRY_SERVICES_FILTERS}" "${SERVICE_NAME}" | ||
_docker_start_replicated_job "${SERVICE_NAME}" | ||
} | ||
|
||
launch_new_gantry() { | ||
local service_name="gantry-$(date +%s)" | ||
docker service create \ | ||
--name "${service_name}" \ | ||
--mode replicated-job \ | ||
--constraint "node.role==manager" \ | ||
--env "GANTRY_SERVICES_EXCLUDED=${GANTRY_SERVICES_EXCLUDED}" \ | ||
--env "GANTRY_SERVICES_EXCLUDED_FILTERS=${GANTRY_SERVICES_EXCLUDED_FILTERS}" \ | ||
--env "GANTRY_SERVICES_FILTERS=${GANTRY_SERVICES_FILTERS}" \ | ||
--label "from-webhook=true" \ | ||
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ | ||
shizunge/gantry | ||
local return_value=$? | ||
docker service logs --raw "${service_name}" | ||
docker service rm "${service_name}" | ||
return "${return_value}" | ||
} | ||
|
||
main() { | ||
launch_new_gantry ${*} | ||
} | ||
|
||
main "${@}" |