You've already forked watchtower
							
							
				mirror of
				https://github.com/containrrr/watchtower.git
				synced 2025-10-31 00:17:44 +02:00 
			
		
		
		
	add pre/post update check lifecycle hooks (#373)
* add pre/post update check lifecycle hooks * update docs for lifecycle hooks * Fix phrasing
This commit is contained in:
		
				
					committed by
					
						 Simon Aronsson
						Simon Aronsson
					
				
			
			
				
	
			
			
			
						parent
						
							1b3db5ed5d
						
					
				
				
					commit
					135467dcf6
				
			| @@ -1,45 +1,53 @@ | ||||
|  | ||||
| ## Executing commands before and after updating | ||||
|  | ||||
| > **DO NOTE**: Both commands are shell commands executed with `sh`, and therefore require the  | ||||
| > **DO NOTE**: These are shell commands executed with `sh`, and therefore require the | ||||
| > container to provide the `sh` executable. | ||||
|  | ||||
| It is possible to execute a *pre-update* command and a *post-update* command  | ||||
| **inside** every container updated by watchtower. The *pre-update* command is  | ||||
| executed before stopping the container, and the *post-update* command is  | ||||
| executed after restarting the container. | ||||
| It is possible to execute _pre/post\-check_ and _pre/post\-update_ commands | ||||
| **inside** every container updated by watchtower. | ||||
|  | ||||
| - The _pre-check_ command is executed for each container prior to every update cycle. | ||||
| - The _pre-update_ command is executed before stopping the container when an update is about to start. | ||||
| - The _post-update_ command is executed after restarting the updated container | ||||
| - The _post-check_ command is executed for each container post every update cycle. | ||||
|  | ||||
| This feature is disabled by default. To enable it, you need to set the option | ||||
| `--enable-lifecycle-hooks` on the command line, or set the environment variable | ||||
| `WATCHTOWER_LIFECYCLE_HOOKS` to `true`. | ||||
|  | ||||
|   | ||||
|  | ||||
| ### Specifying update commands | ||||
|  | ||||
| The commands are specified using docker container labels, with  | ||||
| `com.centurylinklabs.watchtower.lifecycle.pre-update-command` for the *pre-update*  | ||||
| command and `com.centurylinklabs.watchtower.lifecycle.post-update` for the | ||||
| *post-update* command. | ||||
| The commands are specified using docker container labels, the following are currently available: | ||||
|  | ||||
| These labels can be declared as instructions in a Dockerfile: | ||||
| | Type        | Docker Container Label                                 | | ||||
| | ----------- | ------------------------------------------------------ |  | ||||
| | Pre Check   | `com.centurylinklabs.watchtower.lifecycle.pre-check`   | | ||||
| | Pre Update  | `com.centurylinklabs.watchtower.lifecycle.pre-update`  |  | ||||
| | Post Update | `com.centurylinklabs.watchtower.lifecycle.post-update` | | ||||
| | Post Check  | `com.centurylinklabs.watchtower.lifecycle.post-check`  | | ||||
|  | ||||
| These labels can be declared as instructions in a Dockerfile (with some example .sh files): | ||||
|  | ||||
| ```docker | ||||
| LABEL com.centurylinklabs.watchtower.lifecycle.pre-check="/sync.sh" | ||||
| LABEL com.centurylinklabs.watchtower.lifecycle.pre-update="/dump-data.sh" | ||||
| LABEL com.centurylinklabs.watchtower.lifecycle.post-update="/restore-data.sh" | ||||
| LABEL com.centurylinklabs.watchtower.lifecycle.post-check="/send-heartbeat.sh" | ||||
| ``` | ||||
|  | ||||
| Or be specified as part of the `docker run` command line: | ||||
|  | ||||
| ```bash | ||||
| docker run -d \ | ||||
|   --label=com.centurylinklabs.watchtower.lifecycle.pre-check="/sync.sh" \ | ||||
|   --label=com.centurylinklabs.watchtower.lifecycle.pre-update="/dump-data.sh" \ | ||||
|   --label=com.centurylinklabs.watchtower.lifecycle.post-update="/restore-data.sh" \ | ||||
|   someimage | ||||
|   --label=com.centurylinklabs.watchtower.lifecycle.post-check="/send-heartbeat.sh" \ | ||||
| ``` | ||||
|  | ||||
| ### Execution failure | ||||
|  | ||||
| The failure of a command to execute, identified by an exit code different than  | ||||
| The failure of a command to execute, identified by an exit code different than | ||||
| 0, will not prevent watchtower from updating the container. Only an error | ||||
| log statement containing the exit code will be reported. | ||||
| log statement containing the exit code will be reported. | ||||
|   | ||||
| @@ -13,6 +13,8 @@ import ( | ||||
| func Update(client container.Client, params UpdateParams) error { | ||||
| 	log.Debug("Checking containers for updated images") | ||||
|  | ||||
| 	executePreCheck(client, params) | ||||
|  | ||||
| 	containers, err := client.ListContainers(params.Filter) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| @@ -36,12 +38,14 @@ func Update(client container.Client, params UpdateParams) error { | ||||
| 	checkDependencies(containers) | ||||
|  | ||||
| 	if params.MonitorOnly { | ||||
| 		executePostCheck(client, params) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	stopContainersInReversedOrder(containers, client, params) | ||||
| 	restartContainersInSortedOrder(containers, client, params) | ||||
|  | ||||
| 	executePostCheck(client, params) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -123,11 +127,58 @@ func checkDependencies(containers []container.Container) { | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func executePreCheck(client container.Client, params UpdateParams) { | ||||
| 	containers, err := client.ListContainers(params.Filter) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, container := range containers { | ||||
| 		executePreCheckCommand(client, container) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func executePostCheck(client container.Client, params UpdateParams) { | ||||
| 	containers, err := client.ListContainers(params.Filter) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, container := range containers { | ||||
| 		executePostCheckCommand(client, container) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func executePreCheckCommand(client container.Client, container container.Container) { | ||||
| 	command := container.GetLifecyclePreCheckCommand() | ||||
| 	if len(command) == 0 { | ||||
| 		log.Debug("No pre-check command supplied. Skipping") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	log.Info("Executing pre-check command.") | ||||
| 	if err := client.ExecuteCommand(container.ID(), command); err != nil { | ||||
| 		log.Error(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func executePostCheckCommand(client container.Client, container container.Container) { | ||||
| 	command := container.GetLifecyclePostCheckCommand() | ||||
| 	if len(command) == 0 { | ||||
| 		log.Debug("No post-check command supplied. Skipping") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	log.Info("Executing post-check command.") | ||||
| 	if err := client.ExecuteCommand(container.ID(), command); err != nil { | ||||
| 		log.Error(err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func executePreUpdateCommand(client container.Client, container container.Container) { | ||||
|  | ||||
| 	command := container.GetLifecyclePreUpdateCommand() | ||||
| 	if len(command) == 0 { | ||||
| 		log.Debug("No pre-update command supplied. Skipping") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	log.Info("Executing pre-update command.") | ||||
| @@ -146,6 +197,7 @@ func executePostUpdateCommand(client container.Client, newContainerID string) { | ||||
| 	command := newContainer.GetLifecyclePostUpdateCommand() | ||||
| 	if len(command) == 0 { | ||||
| 		log.Debug("No post-update command supplied. Skipping") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	log.Info("Executing post-update command.") | ||||
|   | ||||
| @@ -5,10 +5,22 @@ const ( | ||||
| 	signalLabel     = "com.centurylinklabs.watchtower.stop-signal" | ||||
| 	enableLabel     = "com.centurylinklabs.watchtower.enable" | ||||
| 	zodiacLabel     = "com.centurylinklabs.zodiac.original-image" | ||||
| 	preCheckLabel   = "com.centurylinklabs.watchtower.lifecycle.pre-check" | ||||
| 	postCheckLabel  = "com.centurylinklabs.watchtower.lifecycle.post-check" | ||||
| 	preUpdateLabel  = "com.centurylinklabs.watchtower.lifecycle.pre-update" | ||||
| 	postUpdateLabel = "com.centurylinklabs.watchtower.lifecycle.post-update" | ||||
| ) | ||||
|  | ||||
| // GetLifecyclePreCheckCommand returns the pre-check command set in the container metadata or an empty string | ||||
| func (c Container) GetLifecyclePreCheckCommand() string { | ||||
| 	return c.getLabelValueOrEmpty(preCheckLabel) | ||||
| } | ||||
|  | ||||
| // GetLifecyclePostCheckCommand returns the post-check command set in the container metadata or an empty string | ||||
| func (c Container) GetLifecyclePostCheckCommand() string { | ||||
| 	return c.getLabelValueOrEmpty(postCheckLabel) | ||||
| } | ||||
|  | ||||
| // GetLifecyclePreUpdateCommand returns the pre-update command set in the container metadata or an empty string | ||||
| func (c Container) GetLifecyclePreUpdateCommand() string { | ||||
| 	return c.getLabelValueOrEmpty(preUpdateLabel) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user