Вопрос или проблема
У меня есть интересное поведение в Jenkins.
Оболочка Jenkins не использует мои системные локали.
Jenkins работает как пользователь jenkins
в моей системе.
Вошел как jenkins
через SSH:
locale
выводит:
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_CTYPE=”en_US.UTF-8″
и т.д…
env
показывает переменные LANG
и LANGUAGE
:
LANG=en_US.UTF-8
LANGUAGE=en_US:en
id
показывает ID пользователя:
uid=1008(jenkins) gid=…
Введенные выше команды в оболочке задания Jenkins:
locale
выводит:
LANG=
LANGUAGE=
LC_CTYPE=”POSIX”
и т.д…
env
не показывает переменные LANG
и LANGUAGE
id
показывает ID пользователя (как и ожидалось):
uid=1008(jenkins) gid=…
файлы:
/etc/profile
содержит:
export LANG=en_US.UTF-8
export LANGUAGE=en_US:en
/etc/default/locale
содержит:
export LANG=en_US.UTF-8
export LANGUAGE=en_US:en
скрипт запуска /etc/init.d/jenkins
должен экспортировать системные локали:
# загрузка окружений
if [ -r /etc/default/locale ]; then
. /etc/default/locale
export LANG LANGUAGE
elif [ -r /etc/environment ]; then
. /etc/environment
export LANG LANGUAGE
fi
Конечно, я перезагрузил систему после изменения локалей 😉
Apache также использует системные локали
Моя система – это установка Ubuntu 14.04.
Я что-то пропустил?
Спасибо за внимание!
Надеюсь, кто-то сможет помочь 🙂
Решение:
Это происходит потому, что Jenkins master подключается к slave машине через non-interactive
оболочку, поэтому /etc/profile
не выполняется, и также /etc/default/locale
не имеет никакого эффекта.
non-interactive
оболочки обычно используют ~/.bashrc
.
Практически все детали по этой теме можно найти на askubuntu:
https://askubuntu.com/questions/247738/why-is-etc-profile-not-invoked-for-non-login-shells
добавление в ~/.bashrc
:
export LANG=en_US.UTF-8
export LANGUAGE=en_US:en
это решило мою проблему.
Эта ‘проблема с slave’ также обсуждается здесь:
https://groups.google.com/forum/#!topic/jenkinsci-users/hscDs4pKIoU
https://groups.google.com/forum/#!topic/jenkinsci-users/g0fNnDltqeM
С уважением, whosit
Кроме того, что объяснено в ответе @whosit, оболочка, запущенная с помощью команды Jenkins sh
, наследует переменные окружения процесса Jenkins и выполняется как не интерактивная и не логин оболочка. Это означает, что файл .bashrc
не считывается при каждом вызове sh
, но его значения могут быть видны, так как они наследуются от основного процесса (либо контроллера Jenkins, либо агента).
Это может вызвать путаницу, когда файл .bashrc
или любая другая глобальная переменная обновляется, и новое значение не сразу видно в оболочках, запущенных после изменения.
Существует несколько способов отразить изменения:
- перезагрузить контроллер Jenkins и/или агентов (в зависимости от того, где работает оболочка)
- подключить файл
.bashrc
при каждом вызовеsh
sh """
source .bashrc
printenv
"""
- запустить команду
sh
с директивой shebang, чтобы сказать Jenkins запускать логин оболочку (с--login
, то есть это заставляет новую оболочку считывать файл.bashrc
)
sh """#!/bin/bash --login
printenv
"""
Тот факт, что переменные окружения видны, потому что они наследуются, а не считываются из файлов профиля, не является очень интуитивным и не документируется четко.
В нашем случае невозможно изменить все пайплайны, чтобы добавить директиву shebang или подключать файл .bashrc
каждый раз, когда мы используем команду sh
Jenkins, поэтому мы находим более удобным перезагружать агента каждый раз, когда происходит изменение глобальных настроек окружения (что происходит не очень часто).
Ответ или решение
Вопрос о том, почему Jenkins не использует системные локали, действительно интересен и важен для многих специалистов в области ИТ.
Проблема с локалями в Jenkins
В вашем сценарии Jenkins работает под пользователем jenkins
, и вы заметили, что при запуске команд через Jenkins не устанавливаются соответствующие переменные локали, как это происходит при ведении SSH-сессии. При вводе команд locale
и env
в Jenkins вы видите, что переменные LANG
и LANGUAGE
отсутствуют или имеют значения, отличные от ожидаемых.
Причины
Это поведение связано с тем, что Jenkins запускает shell-команды в неинтерактивной среде. В неинтерактивных оболочках, таких как та, которую использует Jenkins, не выполняются некоторые конфигурационные файлы, такие как /etc/profile
и ~/.bashrc
, которые обычно загружают переменные окружения.
Когда вы входите в систему под пользователем jenkins
через SSH, система запускает интерактивную оболочку и загружает необходимые параметры конфигурации, включая локали. В случае Jenkins, запускаемого как сервис, данный механизм не работает.
Решения
Чтобы исправить ситуацию с локалями в Jenkins, вы можете применить один из следующих подходов:
-
Добавление переменных в
~/.bashrc
:
Откройте файл~/.bashrc
для пользователяjenkins
и добавьте туда строки:export LANG=en_US.UTF-8 export LANGUAGE=en_US:en
Это обеспечит загрузку переменных в среде, когда Jenkins запустит новую оболочку.
-
Перезапуск Jenkins и/или агентов:
Если вы изменяли файл~/.bashrc
, необходимо перезапустить Jenkins или его агентов для применения изменений. Перезапуск сервиса позволит загрузить новую конфигурацию. -
Явная загрузка
~/.bashrc
в скрипте:
В каждом скрипте, выполняемом в Jenkins, можно явно указать загрузку.bashrc
. Например:sh """ source /home/jenkins/.bashrc env """
-
Использование shebang с директивой
--login
:
Вы можете запускать команды в Jenkins с указанием оболочки в верхней части скрипта:sh """#!/bin/bash --login env """
Это будет запускать новую оболочку как входную, что позволит загружать необходимые переменные окружения.
Заключение
Таким образом, для обеспечения работы локалей в Jenkins следует внести изменения в конфигурации окружения, так как Jenkins по умолчанию запускает shell-команды в неинтерактивной оболочке. Решение может заключаться в редактировании файлов конфигурации, явном источнике инструкций оболочки или перезапуске сервисов Jenkins или его агентов. Это необходимо учитывать для корректного выполнения скриптов и предотвращения неожиданных ошибок, связанных с локалями.