From 488111db48a52c3eb51eb1590863c350c2558938 Mon Sep 17 00:00:00 2001 From: Tal Yitzhak Date: Sun, 26 Oct 2025 15:59:46 +0200 Subject: [PATCH] initial work for the operator changes to support installing 3rd party --- api/v1beta/lightrunjavaagent_types.go | 6 + .../crds/lightrunjavaagent_crd.yaml | 7 ++ ...gents.lightrun.com_lightrunjavaagents.yaml | 6 + internal/controller/patch_funcs.go | 116 +++++++++++++++--- lightrun-init-agent/Dockerfile | 4 +- lightrun-init-agent/update_config.sh | 74 +++++++++++ 6 files changed, 196 insertions(+), 17 deletions(-) diff --git a/api/v1beta/lightrunjavaagent_types.go b/api/v1beta/lightrunjavaagent_types.go index 8562cc6..a42b4c6 100644 --- a/api/v1beta/lightrunjavaagent_types.go +++ b/api/v1beta/lightrunjavaagent_types.go @@ -97,6 +97,12 @@ type LightrunJavaAgentSpec struct { // UseSecretsAsMountedFiles determines whether to use secret values as mounted files (true) or as environment variables (false) // +kubebuilder:default=false UseSecretsAsMountedFiles bool `json:"useSecretsAsMountedFiles,omitempty"` + + // MountLibstdc determines whether to mount libstdc++ libraries from the init container to the application container + // This is useful for Alpine-based images that don't have libstdc++ installed + // +kubebuilder:default=false + // +optional + MountLibstdc bool `json:"mountLibstdc,omitempty"` } // LightrunJavaAgentStatus defines the observed state of LightrunJavaAgent diff --git a/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml b/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml index 22de0b0..52ba01d 100644 --- a/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml +++ b/charts/lightrun-operator/crds/lightrunjavaagent_crd.yaml @@ -1,3 +1,4 @@ +--- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -114,6 +115,12 @@ spec: - sharedVolumeMountPath - sharedVolumeName type: object + mountLibstdc: + default: false + description: |- + MountLibstdc determines whether to mount libstdc++ libraries from the init container to the application container + This is useful for Alpine-based images that don't have libstdc++ installed + type: boolean secretName: description: Name of the Secret in the same namespace contains lightrun key and conmpany id diff --git a/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml b/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml index 9e98ec6..52ba01d 100644 --- a/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml +++ b/config/crd/bases/agents.lightrun.com_lightrunjavaagents.yaml @@ -115,6 +115,12 @@ spec: - sharedVolumeMountPath - sharedVolumeName type: object + mountLibstdc: + default: false + description: |- + MountLibstdc determines whether to mount libstdc++ libraries from the init container to the application container + This is useful for Alpine-based images that don't have libstdc++ installed + type: boolean secretName: description: Name of the Secret in the same namespace contains lightrun key and conmpany id diff --git a/internal/controller/patch_funcs.go b/internal/controller/patch_funcs.go index bfd6370..23e0fb9 100644 --- a/internal/controller/patch_funcs.go +++ b/internal/controller/patch_funcs.go @@ -107,6 +107,17 @@ func (r *LightrunJavaAgentReconciler) addVolume(deploymentApplyConfig *appsv1ac. ) } + // Add libstdc volume if MountLibstdc is true + if lightrunJavaAgent.Spec.MountLibstdc { + volumes = append(volumes, + corev1ac.Volume(). + WithName("lightrun-libstdc"). + WithEmptyDir( + corev1ac.EmptyDirVolumeSource(), + ), + ) + } + deploymentApplyConfig.Spec.Template.Spec.WithVolumes(volumes...) } @@ -125,6 +136,12 @@ func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *ap corev1ac.VolumeMount().WithName("lightrun-secret").WithMountPath("/etc/lightrun/secret").WithReadOnly(true), ) } + // If MountLibstdc is enabled, mount the libstdc volume + if spec.MountLibstdc { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-libstdc").WithMountPath("/tmp/libstdc/"), + ) + } // Always set LIGHTRUN_SERVER envVars := []*corev1ac.EnvVarApplyConfiguration{ @@ -145,6 +162,12 @@ func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *ap ), ) } + // If MountLibstdc is enabled, set the MOUNT_LIBSTDC env var to signal the script + if spec.MountLibstdc { + envVars = append(envVars, + corev1ac.EnvVar().WithName("MOUNT_LIBSTDC").WithValue("true"), + ) + } initContainer := corev1ac.Container(). WithName(initContainerName). @@ -177,6 +200,7 @@ func (r *LightrunJavaAgentReconciler) addInitContainer(deploymentApplyConfig *ap }, ), ) + if isImagePullPolicyConfigured { initContainer.WithImagePullPolicy(spec.InitContainer.ImagePullPolicy) } @@ -189,14 +213,32 @@ func (r *LightrunJavaAgentReconciler) patchAppContainers(lightrunJavaAgent *agen for _, targetContainer := range lightrunJavaAgent.Spec.ContainerSelector { if targetContainer == container.Name { found = true - deploymentApplyConfig.Spec.Template.Spec.WithContainers( - corev1ac.Container(). - WithName(container.Name). - WithImage(container.Image). - WithVolumeMounts( - corev1ac.VolumeMount().WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath).WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName), - ), - ) + + // Prepare volume mounts + volumeMounts := []*corev1ac.VolumeMountApplyConfiguration{ + corev1ac.VolumeMount().WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath).WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName), + } + + // Add libstdc volume mount if MountLibstdc is enabled + if lightrunJavaAgent.Spec.MountLibstdc { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-libstdc").WithMountPath("/tmp/libstdc").WithReadOnly(true), + ) + } + + containerConfig := corev1ac.Container(). + WithName(container.Name). + WithImage(container.Image). + WithVolumeMounts(volumeMounts...) + + // Add LD_LIBRARY_PATH environment variable if MountLibstdc is enabled + if lightrunJavaAgent.Spec.MountLibstdc { + containerConfig.WithEnv( + corev1ac.EnvVar().WithName("LD_LIBRARY_PATH").WithValue("/tmp/libstdc"), + ) + } + + deploymentApplyConfig.Spec.Template.Spec.WithContainers(containerConfig) } } } @@ -317,6 +359,17 @@ func (r *LightrunJavaAgentReconciler) addVolumeToStatefulSet(statefulSetApplyCon ) } + // Add libstdc volume if MountLibstdc is true + if lightrunJavaAgent.Spec.MountLibstdc { + volumes = append(volumes, + corev1ac.Volume(). + WithName("lightrun-libstdc"). + WithEmptyDir( + corev1ac.EmptyDirVolumeSource(), + ), + ) + } + statefulSetApplyConfig.Spec.Template.Spec.WithVolumes(volumes...) } @@ -335,6 +388,12 @@ func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetA corev1ac.VolumeMount().WithName("lightrun-secret").WithMountPath("/etc/lightrun/secret").WithReadOnly(true), ) } + // If MountLibstdc is enabled, mount the libstdc volume + if spec.MountLibstdc { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-libstdc").WithMountPath("/tmp/libstdc/"), + ) + } // Always set LIGHTRUN_SERVER envVars := []*corev1ac.EnvVarApplyConfiguration{ @@ -355,6 +414,12 @@ func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetA ), ) } + // If MountLibstdc is enabled, set the MOUNT_LIBSTDC env var to signal the script + if spec.MountLibstdc { + envVars = append(envVars, + corev1ac.EnvVar().WithName("MOUNT_LIBSTDC").WithValue("true"), + ) + } initContainer := corev1ac.Container(). WithName(initContainerName). @@ -387,6 +452,7 @@ func (r *LightrunJavaAgentReconciler) addInitContainerToStatefulSet(statefulSetA }, ), ) + if isImagePullPolicyConfigured { initContainer.WithImagePullPolicy(spec.InitContainer.ImagePullPolicy) } @@ -399,14 +465,32 @@ func (r *LightrunJavaAgentReconciler) patchStatefulSetAppContainers(lightrunJava for _, targetContainer := range lightrunJavaAgent.Spec.ContainerSelector { if targetContainer == container.Name { found = true - statefulSetApplyConfig.Spec.Template.Spec.WithContainers( - corev1ac.Container(). - WithName(container.Name). - WithImage(container.Image). - WithVolumeMounts( - corev1ac.VolumeMount().WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath).WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName), - ), - ) + + // Prepare volume mounts + volumeMounts := []*corev1ac.VolumeMountApplyConfiguration{ + corev1ac.VolumeMount().WithMountPath(lightrunJavaAgent.Spec.InitContainer.SharedVolumeMountPath).WithName(lightrunJavaAgent.Spec.InitContainer.SharedVolumeName), + } + + // Add libstdc volume mount if MountLibstdc is enabled + if lightrunJavaAgent.Spec.MountLibstdc { + volumeMounts = append(volumeMounts, + corev1ac.VolumeMount().WithName("lightrun-libstdc").WithMountPath("/tmp/libstdc").WithReadOnly(true), + ) + } + + containerConfig := corev1ac.Container(). + WithName(container.Name). + WithImage(container.Image). + WithVolumeMounts(volumeMounts...) + + // Add LD_LIBRARY_PATH environment variable if MountLibstdc is enabled + if lightrunJavaAgent.Spec.MountLibstdc { + containerConfig.WithEnv( + corev1ac.EnvVar().WithName("LD_LIBRARY_PATH").WithValue("/tmp/libstdc"), + ) + } + + statefulSetApplyConfig.Spec.Template.Spec.WithContainers(containerConfig) } } } diff --git a/lightrun-init-agent/Dockerfile b/lightrun-init-agent/Dockerfile index 4fd41ac..5191a98 100644 --- a/lightrun-init-agent/Dockerfile +++ b/lightrun-init-agent/Dockerfile @@ -16,7 +16,9 @@ RUN unzip -o /tmp/$FILE -d /agent ;\ # Create secret directory mkdir -p /etc/lightrun/secret && \ chgrp -R 0 /etc/lightrun/secret && \ - chmod -R g=u /etc/lightrun/secret + chmod -R g=u /etc/lightrun/secret && \ + # Install libstdc++ for Alpine-based support + apk add --no-cache libstdc++ # Copy and set permissions for update_config.sh before switching user COPY lightrun-init-agent/update_config.sh /update_config.sh diff --git a/lightrun-init-agent/update_config.sh b/lightrun-init-agent/update_config.sh index a9e58b3..125d3ec 100755 --- a/lightrun-init-agent/update_config.sh +++ b/lightrun-init-agent/update_config.sh @@ -6,6 +6,7 @@ # 3. Merges configuration files # 4. Updates configuration with values from files # 5. Copies the final configuration to destination +# 6. Optionally copies libstdc++ libraries for Alpine-based images set -e @@ -15,6 +16,7 @@ WORK_DIR="${TMP_DIR}/agent-workdir" FINAL_DEST="${TMP_DIR}/agent" CONFIG_MAP_DIR="${TMP_DIR}/cm" SECRET_DIR="/etc/lightrun/secret" +LIBSTDC_DIR="${TMP_DIR}/libstdc" # Function to get value from either environment variable or file get_value() { @@ -150,8 +152,80 @@ cleanup() { rm -rf "${WORK_DIR}" } +# Function to copy libstdc++ libraries +copy_libstdc() { + if [ "${MOUNT_LIBSTDC}" = "true" ]; then + echo "=========================================" + echo "COPYING LIBSTDC++ LIBRARIES" + echo "=========================================" + + # Create the directory + mkdir -p "${LIBSTDC_DIR}" + echo "Created directory: ${LIBSTDC_DIR}" + echo "" + + # Search for and copy libstdc++ libraries + echo "Searching for libstdc++ libraries..." + echo "Running as user: $(id)" + echo "" + + # List of paths to search + for search_path in /usr/lib /lib /usr/lib64 /lib64 /usr/lib/aarch64-linux-gnu /lib/aarch64-linux-gnu /usr/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu; do + if [ -d "${search_path}" ]; then + echo "Checking ${search_path}..." + # Use ls instead of find for simpler logic + lib_files=$(ls "${search_path}"/libstdc++.so* 2>/dev/null || true) + if [ -n "${lib_files}" ]; then + for lib_file in ${lib_files}; do + if [ -f "${lib_file}" ] || [ -L "${lib_file}" ]; then + echo " Found: ${lib_file}" + # Try to copy following symlinks first, then regular copy + if cp -L "${lib_file}" "${LIBSTDC_DIR}/" 2>/dev/null; then + echo " ✓ Copied (following symlink)" + elif cp "${lib_file}" "${LIBSTDC_DIR}/" 2>/dev/null; then + echo " ✓ Copied (as-is)" + else + echo " ✗ Failed to copy" + fi + fi + done + fi + fi + done + + echo "" + echo "----------------------------------------" + echo "Contents of ${LIBSTDC_DIR}:" + if ls -lah "${LIBSTDC_DIR}/" 2>/dev/null; then + echo "----------------------------------------" + else + echo " (empty or not accessible)" + echo "----------------------------------------" + fi + + # Count files (excluding . and ..) + lib_count=$(find "${LIBSTDC_DIR}" -maxdepth 1 -type f -o -type l | wc -l) + if [ "${lib_count}" -gt 0 ]; then + echo "✓ Successfully copied ${lib_count} libstdc++ library file(s)" + else + echo "⚠ WARNING: No libstdc++ libraries were copied!" + echo " Debugging information:" + echo " - Checking if libstdc++ is installed:" + apk info libstdc++ 2>/dev/null || echo " libstdc++ package not found" + echo " - Looking for any libstdc++ files:" + find /usr /lib -name '*libstdc++*' 2>/dev/null | head -10 || echo " No files found" + fi + + echo "=========================================" + echo "" + else + echo "MOUNT_LIBSTDC not set to 'true', skipping libstdc++ library copying" + fi +} + # Main execution main() { + copy_libstdc validate_env_vars setup_working_dir merge_configs