Merge pull request #4860 from dokku/parallel-process-deploys

Add ability to increase the max parallelism when deploying a given process type
This commit is contained in:
Jose Diaz-Gonzalez
2021-10-09 23:35:54 -04:00
committed by GitHub
14 changed files with 99 additions and 13 deletions

View File

@@ -3370,7 +3370,6 @@ Thanks to all the contributors who helped with this release!
- #2388: @josegonzalez Add documentation for proxy ports scheme handling - #2388: @josegonzalez Add documentation for proxy ports scheme handling
- #2389: @josegonzalez Add plugin management documentation - #2389: @josegonzalez Add plugin management documentation
## 0.7.0 ## 0.7.0
Another great minor release! There are no known backwards incompatibilities with this release, though the following may be of interest to our users: Another great minor release! There are no known backwards incompatibilities with this release, though the following may be of interest to our users:
@@ -4756,7 +4755,6 @@ This release pegs Dokku to Docker 1.6.2. Docker 1.7.0 introduced changes in `doc
- #749: @vincentfretin Fix app certificate directory in backup-import/export - #749: @vincentfretin Fix app certificate directory in backup-import/export
- #750: @th4t Remove unintended phrase repetition in installation.md - #750: @th4t Remove unintended phrase repetition in installation.md
## 0.2.0 (2013-11-24) ## 0.2.0 (2013-11-24)
* Added DOKKU_TRACE variable for verbose trace information * Added DOKKU_TRACE variable for verbose trace information

View File

@@ -25,7 +25,7 @@ The [dokku-registry](https://github.com/dokku/dokku-registry) plugin is now buil
- In previous versions of Dokku, the only way to specify a custom `Dockerfile` was to use the `docker-options` plugin to set the `--file` flag for a docker build. As of 0.25.0, the `builder-dockerfile:set` command should be used instead, as outlined in the [docs here](/docs/deployment/builders/dockerfiles.md#changingthe-dockerfile-location). Usage of the old method should be migrated to the new method. - In previous versions of Dokku, the only way to specify a custom `Dockerfile` was to use the `docker-options` plugin to set the `--file` flag for a docker build. As of 0.25.0, the `builder-dockerfile:set` command should be used instead, as outlined in the [docs here](/docs/deployment/builders/dockerfiles.md#changingthe-dockerfile-location). Usage of the old method should be migrated to the new method.
- The `--rm` and `--rm-container` flags may be specified but no longer have any effect on `dokku run`. - The `--rm` and `--rm-container` flags may be specified but no longer have any effect on `dokku run`.
- The `--detach` flag is deprecated in favor of the `run:detached` command. - The `--detach` flag is deprecated in favor of the `run:detached` command.
- The `DOKKU_SCALE` file is deprecated. Please see the [process management documentation](/docs/processes/process-management.md#manually-managing-process-scaling) for more information on it's replacement with the `formations` key of the `app.json` file. - The `DOKKU_SCALE` file is deprecated. Please see the [process management documentation](/docs/processes/process-management.md#manually-managing-process-scaling) for more information on it's replacement with the `formation` key of the `app.json` file.
- The hooks `post-release-buildpack`, `post-release-dockerfile`, and `post-release-pack` are deprecated in favor of `post-release-builder`. See the [plugin triggers documentation](https://dokku.com/docs/development/plugin-triggers/#post-release-builder) for more details. - The hooks `post-release-buildpack`, `post-release-dockerfile`, and `post-release-pack` are deprecated in favor of `post-release-builder`. See the [plugin triggers documentation](https://dokku.com/docs/development/plugin-triggers/#post-release-builder) for more details.
## Removals ## Removals

View File

@@ -37,9 +37,9 @@ Once set, you may re-enable it by setting a blank value for `disable-chown`:
dokku scheduler-docker-local:set node-js-app disable-chown dokku scheduler-docker-local:set node-js-app disable-chown
``` ```
### Deploying Process Types in parallel ### Deploying Process Types in Parallel
> New as of 25.5 > New as of 0.25.5
By default, Dokku deploys an app's processes one-by-one in order, with the `web` process being deployed first. Deployment parallelism may be achieved by setting the `parallel-schedule-count` property, which defaults to `1`. Increasing this number increases the number of process types that may be deployed in parallel (with the web process being the exception). By default, Dokku deploys an app's processes one-by-one in order, with the `web` process being deployed first. Deployment parallelism may be achieved by setting the `parallel-schedule-count` property, which defaults to `1`. Increasing this number increases the number of process types that may be deployed in parallel (with the web process being the exception).
@@ -60,6 +60,37 @@ Container scheduling output is shown in the order it is received, and thus may b
Note that increasing the value of `parallel-schedule-count` may significantly impact CPU utilization on your host as your app containers - and their respective processes - start up. Setting a value higher than the number of available CPUs is discouraged. It is recommended that users carefully set this value so as not to overburden their server. Note that increasing the value of `parallel-schedule-count` may significantly impact CPU utilization on your host as your app containers - and their respective processes - start up. Setting a value higher than the number of available CPUs is discouraged. It is recommended that users carefully set this value so as not to overburden their server.
#### Increasing parallelism within a process deploy
> New as of 0.26.0
By default, Dokku will deploy one instance of a given process type at a time. This can be increased by customizing the `app.json` `formation` key to include a `max_parallel` key for the given process type.
An `app.json` file can be committed to the root of the pushed app repository, and must be within the built image artifact in the image's working directory as shown below.
- Buildpacks: `/app/app.json`
- Dockerfile: `WORKDIR/app.json` or `/app.json` (if no working directory specified)
- Docker Image: `WORKDIR/app.json` or `/app.json` (if no working directory specified)
The `formation` key should be specified as follows in the `app.json` file:
```Procfile
{
"formation": {
"web": {
"max_parallel": 1
},
"worker": {
"max_parallel": 4
}
}
}
```
Omitting or removing the entry will result in parallelism for that process type to return to 1 entry at a time. This can be combined with the `parallel-schedule-count` property to speed up deployments.
Note that increasing the value of `max_parallel` may significantly impact CPU utilization on your host as your app containers - and their respective processes - start up. Setting a value higher than the number of available CPUs is discouraged. It is recommended that users carefully set this value so as not to overburden their server.
## Implemented Triggers ## Implemented Triggers
This plugin implements various functionality through `plugn` triggers to integrate with Docker for running apps on a single server. The following functionality is supported by the `scheduler-docker-local` plugin. This plugin implements various functionality through `plugn` triggers to integrate with Docker for running apps on a single server. The following functionality is supported by the `scheduler-docker-local` plugin.

View File

@@ -74,6 +74,21 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
# TODO # TODO
``` ```
### `app-json-process-deploy-parallelism`
- Description: Decides the parallelism to use when deploying a given process type. The default is 1 process entry at a type.
- Invoked by: `dokku deploy`
- Arguments: `$APP $PROCESS_TYPE`
- Example:
```shell
#!/usr/bin/env bash
set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
# TODO
```
### `app-maybe-create` ### `app-maybe-create`
- Description: Creates an app (gated by whether this is globally enabled or not) - Description: Creates an app (gated by whether this is globally enabled or not)
@@ -962,7 +977,7 @@ set -eo pipefail; [[ $DOKKU_TRACE ]] && set -x
- Description: Return the port for a given app container - Description: Return the port for a given app container
- Invoked by: `internally triggered by a deploy` - Invoked by: `internally triggered by a deploy`
- Arguments: `$APP $PROC_TYPE $CONTAINER_ID $IS_HEROKUISH_CONTAINER` - Arguments: `$APP $PROCESS_TYPE $CONTAINER_ID $IS_HEROKUISH_CONTAINER`
- Example: - Example:
```shell ```shell

View File

@@ -131,7 +131,7 @@ dokku ps:scale --skip-deploy node-js-app web=1
#### Manually managing process scaling #### Manually managing process scaling
> Using a `formation` key in an `app.json` file disables the ability to use `ps:scale` for scaling. > Using a `formation` key in an `app.json` file with _any_ `quantity` specified disables the ability to use `ps:scale` for scaling.
An `app.json` file can be committed to the root of the pushed app repository, and must be within the built image artifact in the image's working directory as shown below. An `app.json` file can be committed to the root of the pushed app repository, and must be within the built image artifact in the image's working directory as shown below.

View File

@@ -0,0 +1 @@
hook

View File

@@ -0,0 +1 @@
hook

View File

@@ -6,3 +6,4 @@
/subcommands/* /subcommands/*
/triggers /triggers
/triggers/* /triggers/*
/app-json-process-deploy-parallelism

View File

@@ -1,5 +1,5 @@
SUBCOMMANDS = subcommands/report subcommands/set SUBCOMMANDS = subcommands/report subcommands/set
TRIGGERS = triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy triggers/report TRIGGERS = triggers/app-json-process-deploy-parallelism triggers/install triggers/post-delete triggers/post-deploy triggers/pre-deploy triggers/report
BUILD = commands subcommands triggers BUILD = commands subcommands triggers
PLUGIN_NAME = app-json PLUGIN_NAME = app-json

View File

@@ -39,7 +39,8 @@ type CronCommand struct {
// Formation is a struct that represents the scale for a process from an app.json file // Formation is a struct that represents the scale for a process from an app.json file
type Formation struct { type Formation struct {
Quantity int `json:"quantity"` Quantity *int `json:"quantity"`
MaxParallel *int `json:"max_parallel"`
} }
// GetAppjsonDirectory returns the directory containing a given app's extracted app.json file // GetAppjsonDirectory returns the directory containing a given app's extracted app.json file

View File

@@ -500,7 +500,9 @@ func setScale(appName string, image string) error {
clearExisting := false clearExisting := false
args := []string{appName, strconv.FormatBool(skipDeploy), strconv.FormatBool(clearExisting)} args := []string{appName, strconv.FormatBool(skipDeploy), strconv.FormatBool(clearExisting)}
for processType, formation := range appJSON.Formation { for processType, formation := range appJSON.Formation {
args = append(args, fmt.Sprintf("%s=%d", processType, formation.Quantity)) if formation.Quantity != nil {
args = append(args, fmt.Sprintf("%s=%d", processType, *formation.Quantity))
}
} }
if len(args) == 3 { if len(args) == 3 {
@@ -567,7 +569,7 @@ func injectDokkuScale(appName string, image string) error {
} }
appJSON.Formation[processType] = Formation{ appJSON.Formation[processType] = Formation{
Quantity: quantity, Quantity: &quantity,
} }
} }

View File

@@ -18,6 +18,10 @@ func main() {
var err error var err error
switch trigger { switch trigger {
case "app-json-process-deploy-parallelism":
appName := flag.Arg(0)
processType := flag.Arg(1)
err = appjson.TriggerAppJSONProcessDeployParallelism(appName, processType)
case "install": case "install":
err = appjson.TriggerInstall() err = appjson.TriggerInstall()
case "post-delete": case "post-delete":

View File

@@ -8,6 +8,32 @@ import (
"github.com/dokku/dokku/plugins/common" "github.com/dokku/dokku/plugins/common"
) )
// TriggerAppJSONProcessDeployParallelism returns the max number of processes to deploy in parallel
func TriggerAppJSONProcessDeployParallelism(appName string, processType string) error {
appJSON, err := getAppJSON(appName)
if err != nil {
return err
}
parallelism := 1
for procType, formation := range appJSON.Formation {
if procType != processType {
continue
}
if formation.MaxParallel == nil {
continue
}
if *formation.MaxParallel > 0 {
parallelism = *formation.MaxParallel
}
}
fmt.Println(parallelism)
return nil
}
// TriggerInstall initializes app restart policies // TriggerInstall initializes app restart policies
func TriggerInstall() error { func TriggerInstall() error {
if err := common.PropertySetup("app-json"); err != nil { if err := common.PropertySetup("app-json"); err != nil {

View File

@@ -27,11 +27,17 @@ main() {
done done
fi fi
local PROCESS_TMP_FILE=$(mktemp "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")
trap "rm -rf '$PROCESS_TMP_FILE' >/dev/null" RETURN INT TERM
while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do while [[ $CONTAINER_INDEX -le $PROC_COUNT ]]; do
export DOKKU_CHECKS_DISABLED="$DOKKU_CHECKS_DISABLED" echo "$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/bin/scheduler-deploy-process-container $APP $IMAGE_SOURCE_TYPE $IMAGE $IMAGE_TAG $PROC_TYPE $PROC_COUNT $CONTAINER_INDEX" >>"$PROCESS_TMP_FILE"
"$PLUGIN_AVAILABLE_PATH/scheduler-docker-local/bin/scheduler-deploy-process-container" "$APP" "$IMAGE_SOURCE_TYPE" "$IMAGE" "$IMAGE_TAG" "$PROC_TYPE" "$PROC_COUNT" "$CONTAINER_INDEX"
CONTAINER_INDEX=$((CONTAINER_INDEX + 1)) CONTAINER_INDEX=$((CONTAINER_INDEX + 1))
done done
PARALLEL_DEPLOY_COUNT="$(plugn trigger "app-json-process-deploy-parallelism" "$APP" "$PROC_TYPE")"
DOKKU_CHECKS_DISABLED="$DOKKU_CHECKS_DISABLED" parallel --will-cite --halt soon,fail=1 --jobs "$PARALLEL_DEPLOY_COUNT" --ungroup <"$PROCESS_TMP_FILE"
# cleanup when we scale down # cleanup when we scale down
if [[ "$PROC_COUNT" == 0 ]]; then if [[ "$PROC_COUNT" == 0 ]]; then
local CONTAINER_IDX_OFFSET=0 local CONTAINER_IDX_OFFSET=0