|
|
a89620 |
From 6016283dfdcb45bf750f96715fc653a4c0904bca Mon Sep 17 00:00:00 2001
|
|
|
a89620 |
From: Damien Ciabrini <dciabrin@redhat.com>
|
|
|
a89620 |
Date: Fri, 28 Jun 2019 13:34:40 +0200
|
|
|
a89620 |
Subject: [PATCH] podman: only use exec to manage container's lifecycle
|
|
|
a89620 |
|
|
|
a89620 |
Under heavy IO load, podman may be impacted and take a long time
|
|
|
a89620 |
to execute some actions. If that takes more than the default
|
|
|
a89620 |
20s container monitoring timeout, containers will restart unexpectedly.
|
|
|
a89620 |
|
|
|
a89620 |
Replace all IO-sensitive podman calls (inspect, exists...) by
|
|
|
a89620 |
equivalent "podman exec" calls, because the latter command seems
|
|
|
a89620 |
less prone to performance degradation under IO load.
|
|
|
a89620 |
|
|
|
a89620 |
With this commit, the resource agent now requires podman 1.0.2+,
|
|
|
a89620 |
because it relies on of two different patches [1,2] that improve
|
|
|
a89620 |
IO performance and enable to distinguish "container stopped"
|
|
|
a89620 |
"container doesn't exist" error codes.
|
|
|
a89620 |
|
|
|
a89620 |
Tested on an OpenStack environment with podman 1.0.2, with the
|
|
|
a89620 |
following scenario:
|
|
|
a89620 |
. regular start/stop/monitor operations
|
|
|
a89620 |
. probe operations (pcs resource cleanup/refresh)
|
|
|
a89620 |
. unmanage/manage operations
|
|
|
a89620 |
. reboot
|
|
|
a89620 |
|
|
|
a89620 |
[1] https://github.com/containers/libpod/commit/90b835db69d589de559462d988cb3fae5cf1ef49
|
|
|
a89620 |
[2] https://github.com/containers/libpod/commit/a19975f96d2ee7efe186d9aa0be42285cfafa3f4
|
|
|
a89620 |
---
|
|
|
a89620 |
heartbeat/podman | 75 ++++++++++++++++++++++++------------------------
|
|
|
a89620 |
1 file changed, 37 insertions(+), 38 deletions(-)
|
|
|
a89620 |
|
|
|
a89620 |
diff --git a/heartbeat/podman b/heartbeat/podman
|
|
|
a89620 |
index 51f6ba883..8fc2c4695 100755
|
|
|
a89620 |
--- a/heartbeat/podman
|
|
|
a89620 |
+++ b/heartbeat/podman
|
|
|
a89620 |
@@ -129,9 +129,6 @@ the health of the container. This command must return 0 to indicate that
|
|
|
a89620 |
the container is healthy. A non-zero return code will indicate that the
|
|
|
a89620 |
container has failed and should be recovered.
|
|
|
a89620 |
|
|
|
a89620 |
-If 'podman exec' is supported, it is used to execute the command. If not,
|
|
|
a89620 |
-nsenter is used.
|
|
|
a89620 |
-
|
|
|
a89620 |
Note: Using this method for monitoring processes inside a container
|
|
|
a89620 |
is not recommended, as containerd tries to track processes running
|
|
|
a89620 |
inside the container and does not deal well with many short-lived
|
|
|
a89620 |
@@ -192,17 +189,13 @@ monitor_cmd_exec()
|
|
|
a89620 |
local rc=$OCF_SUCCESS
|
|
|
a89620 |
local out
|
|
|
a89620 |
|
|
|
a89620 |
- if [ -z "$OCF_RESKEY_monitor_cmd" ]; then
|
|
|
a89620 |
- return $rc
|
|
|
a89620 |
- fi
|
|
|
a89620 |
-
|
|
|
a89620 |
out=$(podman exec ${CONTAINER} $OCF_RESKEY_monitor_cmd 2>&1)
|
|
|
a89620 |
rc=$?
|
|
|
a89620 |
- if [ $rc -eq 127 ]; then
|
|
|
a89620 |
- ocf_log err "monitor cmd failed (rc=$rc), output: $out"
|
|
|
a89620 |
- ocf_exit_reason "monitor_cmd, ${OCF_RESKEY_monitor_cmd} , not found within container."
|
|
|
a89620 |
- # there is no recovering from this, exit immediately
|
|
|
a89620 |
- exit $OCF_ERR_ARGS
|
|
|
a89620 |
+ # 125: no container with name or ID ${CONTAINER} found
|
|
|
a89620 |
+ # 126: container state improper (not running)
|
|
|
a89620 |
+ # 127: any other error
|
|
|
a89620 |
+ if [ $rc -eq 125 ] || [ $rc -eq 126 ]; then
|
|
|
a89620 |
+ rc=$OCF_NOT_RUNNING
|
|
|
a89620 |
elif [ $rc -ne 0 ]; then
|
|
|
a89620 |
ocf_exit_reason "monitor cmd failed (rc=$rc), output: $out"
|
|
|
a89620 |
rc=$OCF_ERR_GENERIC
|
|
|
a89620 |
@@ -215,7 +208,16 @@ monitor_cmd_exec()
|
|
|
a89620 |
|
|
|
a89620 |
container_exists()
|
|
|
a89620 |
{
|
|
|
a89620 |
- podman inspect --format {{.State.Running}} $CONTAINER | egrep '(true|false)' >/dev/null 2>&1
|
|
|
a89620 |
+ local rc
|
|
|
a89620 |
+ local out
|
|
|
a89620 |
+
|
|
|
a89620 |
+ out=$(podman exec ${CONTAINER} $OCF_RESKEY_monitor_cmd 2>&1)
|
|
|
a89620 |
+ rc=$?
|
|
|
a89620 |
+ # 125: no container with name or ID ${CONTAINER} found
|
|
|
a89620 |
+ if [ $rc -ne 125 ]; then
|
|
|
a89620 |
+ return 0
|
|
|
a89620 |
+ fi
|
|
|
a89620 |
+ return 1
|
|
|
a89620 |
}
|
|
|
a89620 |
|
|
|
a89620 |
remove_container()
|
|
|
a89620 |
@@ -236,30 +238,30 @@ remove_container()
|
|
|
a89620 |
|
|
|
a89620 |
podman_simple_status()
|
|
|
a89620 |
{
|
|
|
a89620 |
- local val
|
|
|
a89620 |
-
|
|
|
a89620 |
- # retrieve the 'Running' attribute for the container
|
|
|
a89620 |
- val=$(podman inspect --format {{.State.Running}} $CONTAINER 2>/dev/null)
|
|
|
a89620 |
- if [ $? -ne 0 ]; then
|
|
|
a89620 |
- #not running as a result of container not being found
|
|
|
a89620 |
- return $OCF_NOT_RUNNING
|
|
|
a89620 |
- fi
|
|
|
a89620 |
+ local rc
|
|
|
a89620 |
|
|
|
a89620 |
- if ocf_is_true "$val"; then
|
|
|
a89620 |
- # container exists and is running
|
|
|
a89620 |
- return $OCF_SUCCESS
|
|
|
a89620 |
+ # simple status is implemented via podman exec
|
|
|
a89620 |
+ # everything besides success is considered "not running"
|
|
|
a89620 |
+ monitor_cmd_exec
|
|
|
a89620 |
+ rc=$?
|
|
|
a89620 |
+ if [ $rc -ne $OCF_SUCCESS ]; then
|
|
|
a89620 |
+ rc=$OCF_NOT_RUNNING;
|
|
|
a89620 |
fi
|
|
|
a89620 |
-
|
|
|
a89620 |
- return $OCF_NOT_RUNNING
|
|
|
a89620 |
+ return $rc
|
|
|
a89620 |
}
|
|
|
a89620 |
|
|
|
a89620 |
podman_monitor()
|
|
|
a89620 |
{
|
|
|
a89620 |
- if [ -z "$OCF_RESKEY_monitor_cmd" ]; then
|
|
|
a89620 |
- podman_simple_status
|
|
|
a89620 |
- return $?
|
|
|
a89620 |
- fi
|
|
|
a89620 |
+ # We rely on running podman exec to monitor the container
|
|
|
a89620 |
+ # state because that command seems to be less prone to
|
|
|
a89620 |
+ # performance issue under IO load.
|
|
|
a89620 |
+ #
|
|
|
a89620 |
+ # For probes to work, we expect cmd_exec to be able to report
|
|
|
a89620 |
+ # when a container is not running. Here, we're not interested
|
|
|
a89620 |
+ # in distinguishing whether it's stopped or non existing
|
|
|
a89620 |
+ # (there's function container_exists for that)
|
|
|
a89620 |
monitor_cmd_exec
|
|
|
a89620 |
+ return $?
|
|
|
a89620 |
}
|
|
|
a89620 |
|
|
|
a89620 |
podman_create_mounts() {
|
|
|
a89620 |
@@ -416,14 +418,6 @@ podman_validate()
|
|
|
a89620 |
exit $OCF_ERR_CONFIGURED
|
|
|
a89620 |
fi
|
|
|
a89620 |
|
|
|
a89620 |
- if [ -n "$OCF_RESKEY_monitor_cmd" ]; then
|
|
|
a89620 |
- podman exec --help >/dev/null 2>&1
|
|
|
a89620 |
- if [ ! $? ]; then
|
|
|
a89620 |
- ocf_log info "checking for nsenter, which is required when 'monitor_cmd' is specified"
|
|
|
a89620 |
- check_binary nsenter
|
|
|
a89620 |
- fi
|
|
|
a89620 |
- fi
|
|
|
a89620 |
-
|
|
|
a89620 |
image_exists
|
|
|
a89620 |
if [ $? -ne 0 ]; then
|
|
|
a89620 |
ocf_exit_reason "base image, ${OCF_RESKEY_image}, could not be found."
|
|
|
a89620 |
@@ -457,6 +451,11 @@ fi
|
|
|
a89620 |
|
|
|
a89620 |
CONTAINER=$OCF_RESKEY_name
|
|
|
a89620 |
|
|
|
a89620 |
+# Note: we currently monitor podman containers by with the "podman exec"
|
|
|
a89620 |
+# command, so make sure that invocation is always valid by enforcing the
|
|
|
a89620 |
+# exec command to be non-empty
|
|
|
a89620 |
+: ${OCF_RESKEY_monitor_cmd:=/bin/true}
|
|
|
a89620 |
+
|
|
|
a89620 |
case $__OCF_ACTION in
|
|
|
a89620 |
meta-data) meta_data
|
|
|
a89620 |
exit $OCF_SUCCESS;;
|