@@ -1007,16 +1007,30 @@ sinks:
1007
1007
)
1008
1008
}
1009
1009
1010
- /// Create the specification of the Vector log agent container
1010
+ /// Create the specification of the Vector log agent container.
1011
+ ///
1012
+ /// The vector process is not running as PID 1, so a Kubernetes SIGTERM will be have no effect.
1013
+ /// Instead, the vector process can be shut down by creating a file below {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR},
1014
+ /// e.g. {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}/{SHUTDOWN_FILE}. This way logs from the products will always be shipped,
1015
+ /// as the vector container will be the last one to terminate. A specific container must be chosen, which has the responsibility
1016
+ /// to create a file after it has properly shut down. It should be the one taking the longest to shut down.
1017
+ /// E.g. for hdfs the lifetime of vector will be bound to the datanode container and not to the zkfc container.
1018
+ /// We *could* have different shutdown trigger files for all application containers and wait for all containers
1019
+ /// to terminate, but that seems rather complicated and will be added once needed. Additionally, you should remove
1020
+ /// the shutdown marker file on startup of the application, as the application container can crash for any reason
1021
+ /// and get restarted. If you don't remove the shutdown file on startup, the vector container will crashloop forever,
1022
+ /// as it will start and shut down immediately after!
1011
1023
///
1012
1024
/// ```
1013
1025
/// use stackable_operator::{
1014
1026
/// builder::{
1027
+ /// ContainerBuilder,
1015
1028
/// meta::ObjectMetaBuilder,
1016
1029
/// PodBuilder,
1017
1030
/// resources::ResourceRequirementsBuilder
1018
1031
/// },
1019
- /// product_logging,
1032
+ /// product_logging::{self, framework:: {create_vector_shutdown_file_command, remove_vector_shutdown_file_command}},
1033
+ /// utils::COMMON_BASH_TRAP_FUNCTIONS,
1020
1034
/// };
1021
1035
/// use k8s_openapi::apimachinery::pkg::api::resource::Quantity;
1022
1036
/// # use stackable_operator::{
@@ -1026,6 +1040,8 @@ sinks:
1026
1040
/// # };
1027
1041
/// # use strum::{Display, EnumIter};
1028
1042
/// #
1043
+ /// # pub const STACKABLE_LOG_DIR: &str = "/stackable/log";
1044
+ /// #
1029
1045
/// # #[derive(Clone, Display, Eq, EnumIter, Ord, PartialEq, PartialOrd)]
1030
1046
/// # pub enum Container {
1031
1047
/// # Vector,
@@ -1051,6 +1067,27 @@ sinks:
1051
1067
/// .with_memory_limit("1Gi")
1052
1068
/// .build();
1053
1069
///
1070
+ /// pod_builder.add_container(
1071
+ /// ContainerBuilder::new("application")
1072
+ /// .unwrap()
1073
+ /// .image_from_product_image(&resolved_product_image)
1074
+ /// .args(vec![format!(
1075
+ /// "\
1076
+ /// {COMMON_BASH_TRAP_FUNCTIONS}
1077
+ /// {remove_vector_shutdown_file_command}
1078
+ /// prepare_signal_handlers
1079
+ /// my-application start &
1080
+ /// wait_for_termination $!
1081
+ /// {create_vector_shutdown_file_command}
1082
+ /// ",
1083
+ /// remove_vector_shutdown_file_command =
1084
+ /// remove_vector_shutdown_file_command(STACKABLE_LOG_DIR),
1085
+ /// create_vector_shutdown_file_command =
1086
+ /// create_vector_shutdown_file_command(STACKABLE_LOG_DIR),
1087
+ /// )])
1088
+ /// .build(),
1089
+ /// );
1090
+ ///
1054
1091
/// if logging.enable_vector_agent {
1055
1092
/// pod_builder.add_container(product_logging::framework::vector_container(
1056
1093
/// &resolved_product_image,
@@ -1082,15 +1119,28 @@ pub fn vector_container(
1082
1119
ContainerBuilder :: new ( "vector" )
1083
1120
. unwrap ( )
1084
1121
. image_from_product_image ( image)
1085
- . command ( vec ! [ "bash" . into( ) , "-c" . into( ) ] )
1122
+ . command ( vec ! [
1123
+ "/bin/bash" . to_string( ) ,
1124
+ "-x" . to_string( ) ,
1125
+ "-euo" . to_string( ) ,
1126
+ "pipefail" . to_string( ) ,
1127
+ "-c" . to_string( ) ,
1128
+ ] )
1129
+ // The following code is an alternative approach which can get SIGTERM terminated as well as via writing a file.
1130
+ // It is left in here, as it needed some effort to get it right and can be helpful in the future.
1131
+ // bash -c 'sleep 1 && if [ ! -f \"{STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}/{SHUTDOWN_FILE}\" ]; then mkdir -p {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR} && inotifywait -qq --event create {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}; fi && kill 1' &
1132
+ // exec vector --config {STACKABLE_CONFIG_DIR}/{VECTOR_CONFIG_FILE}
1086
1133
. args ( vec ! [ format!(
1087
1134
"\
1088
- vector --config {STACKABLE_CONFIG_DIR}/{VECTOR_CONFIG_FILE} & vector_pid=$! && \
1089
- if [ ! -f \" {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}/{SHUTDOWN_FILE}\" ]; then \
1090
- mkdir -p {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR} && \
1091
- inotifywait -qq --event create {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}; \
1092
- fi && \
1093
- kill $vector_pid"
1135
+ # Vector will ignore SIGTERM (as PID != 1) and must be shut down by writing a shutdown trigger file
1136
+ vector --config {STACKABLE_CONFIG_DIR}/{VECTOR_CONFIG_FILE} & vector_pid=$!
1137
+ if [ ! -f \" {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}/{SHUTDOWN_FILE}\" ]; then
1138
+ mkdir -p {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR} && \
1139
+ inotifywait -qq --event create {STACKABLE_LOG_DIR}/{VECTOR_LOG_DIR}; \
1140
+ fi
1141
+ sleep 1
1142
+ kill $vector_pid
1143
+ "
1094
1144
) ] )
1095
1145
. add_env_var ( "VECTOR_LOG" , log_level. to_vector_literal ( ) )
1096
1146
. add_volume_mount ( config_volume_name, STACKABLE_CONFIG_DIR )
@@ -1099,7 +1149,8 @@ kill $vector_pid"
1099
1149
. build ( )
1100
1150
}
1101
1151
1102
- /// Command to shut down the Vector instance
1152
+ /// Command to create a shutdown file for the vector container.
1153
+ /// Please delete it before starting your application using [`remove_vector_shutdown_file_command`].
1103
1154
///
1104
1155
/// # Example
1105
1156
///
@@ -1112,8 +1163,9 @@ kill $vector_pid"
1112
1163
/// const STACKABLE_LOG_DIR: &str = "/stackable/log";
1113
1164
///
1114
1165
/// let args = vec![
1115
- /// "echo Perform initialization tasks ...".into(),
1116
- /// product_logging::framework::shutdown_vector_command(STACKABLE_LOG_DIR),
1166
+ /// product_logging::framework::remove_vector_shutdown_file_command(STACKABLE_LOG_DIR),
1167
+ /// "echo Perform some tasks ...".into(),
1168
+ /// product_logging::framework::create_vector_shutdown_file_command(STACKABLE_LOG_DIR),
1117
1169
/// ];
1118
1170
///
1119
1171
/// let container = ContainerBuilder::new("init")
@@ -1124,13 +1176,19 @@ kill $vector_pid"
1124
1176
/// .add_volume_mount("log", STACKABLE_LOG_DIR)
1125
1177
/// .build();
1126
1178
/// ```
1127
- pub fn shutdown_vector_command ( stackable_log_dir : & str ) -> String {
1179
+ pub fn create_vector_shutdown_file_command ( stackable_log_dir : & str ) -> String {
1128
1180
format ! (
1129
1181
"mkdir -p {stackable_log_dir}/{VECTOR_LOG_DIR} && \
1130
1182
touch {stackable_log_dir}/{VECTOR_LOG_DIR}/{SHUTDOWN_FILE}"
1131
1183
)
1132
1184
}
1133
1185
1186
+ /// Use this command to remove the shutdown file (if it exists) created by [`create_vector_shutdown_file_command`].
1187
+ /// You should execute this command before starting your application.
1188
+ pub fn remove_vector_shutdown_file_command ( stackable_log_dir : & str ) -> String {
1189
+ format ! ( "rm -f {stackable_log_dir}/{VECTOR_LOG_DIR}/{SHUTDOWN_FILE}" )
1190
+ }
1191
+
1134
1192
#[ cfg( test) ]
1135
1193
mod tests {
1136
1194
use super :: * ;
0 commit comments