вступление
Летом у меня была возможность немного поиграть с Дженкинсом в Кубернетесе . Точнее, я хотел посмотреть, как лучше всего запустить Docker Workflow Plugin .
Итак, идея заключалась в том, чтобы иметь Pod, работающий с Jenkins, и использовать его для запуска сборок, которые определены с помощью Docker Workflow Plugin . После долгих чтений и экспериментов я обнаружил, что есть много способов сделать это, с разными плюсами и минусами.
В этом сообщении рассматриваются все доступные варианты. Более конкретно:
- Строит работает прямо на Мастер
- Использование плагина Docker для запуска Slaves
- Использование Docker Plugin и Docker в Docker
- Использование клиентов Swarm
- Рой с докером в докере
Прежде чем я рассмотрю все возможные настройки, я думаю, что было бы полезно описать все эти плагины.
Docker Plugin
Плагин Jenkins, который использует Docker для создания и использования рабов. Он использует http для связи с Docker и создания новых контейнеров. Эти контейнеры должны быть готовы только для Java, а также запускать SSHD , чтобы мастер мог подключиться к ним и выполнить свою магию. В Интернете есть много изображений для ведомых контейнеров, самым популярным на момент моего присоединения был раб Еварга Дженкинс .
Плагин можно использовать, но он немного ненадежен, так как создает контейнер Docker, но иногда ему не удается подключиться к ведомому устройству и повторять попытки (обычно требуется от 2 до 3 попыток) . Опробовано много разных ведомых образов и много разных методов аутентификации (пароль, аутентификация ключа и т. Д.) С похожим опытом.
роиться
Наличие плагина для создания ведомого является одним из подходов. Другой — «Приведи своих рабов», и это в значительной степени то, что такое рой. Идея состоит в том, что мастер Jenkins запускает плагин Swarm, а пользователи отвечают за запуск клиентов Swarm (это всего лишь процесс Java).
1
|
java -jar /path/to/swarm-client.jar http: //jenkins.master:8080 |
Клиент подключается к мастеру и сообщает, что он запущен и работает. Затем мастер может начать сборку на клиенте.
Docker Workflow Plugin
Этот плагин позволяет использовать образы и контейнеры Docker в сценариях рабочего процесса или, другими словами, выполнять шаги рабочего процесса внутри контейнеров Docker и создавать Docker из сценариев рабочего процесса.
Почему?
Инкапсулировать все требования вашей сборки в образ Docker и не беспокоиться о том, как их установить и настроить.
Вот как выглядит пример сценария Docker Workflow:
1
2
3
4
5
6
|
node( 'docker' ) { docker.image( 'maven' ).inside { sh 'mvn clean install' } } |
Примечание . Вам не нужно использовать подключаемый модуль Docker для подключаемого модуля Docker Workflow .
Также : плагин Docker Workflow использует бинарный файл Docker . Это означает, что вам нужно установить Docker- клиент везде, где вы собираетесь использовать Docker Workflow Plugin .
Почти забыл : « Исполнитель » сборки и контейнеры, которые участвуют в рабочем процессе, должны совместно использовать рабочее пространство проекта. Я не буду вдаваться в подробности, прямо сейчас. Просто имейте в виду, что для этого обычно требуется доступ к определенным путям на хосте докера (или к некоторым файлам с общей файловой системой) . Невыполнение этих требований приводит к «трудным для обнаружения» проблемам, таким как сборочные процессы, ведущиеся вечно и т.д.
Теперь мы готовы посмотреть, каковы возможные настройки.
Нет рабов
Это самый простой подход. В нем не задействованы подчиненные Jenkins , сборки выполняются непосредственно на главном сервере путем настройки фиксированного пула исполнителей.
Поскольку нет подчиненных устройств, для контейнера, на котором работает сам Jenkins , необходимо установить двоичный файл Docker и настроить его так, чтобы он указывал на фактический хост Docker .
Как использовать докер-хост внутри Kubernetes?
Есть два подхода:
- Использование API Kubernetes
- Путем монтирования /var/run/docker.sock
Вы можете сделать (1), используя простой скрипт оболочки, подобный приведенному ниже.
1
2
3
4
5
|
#!/bin/bash KUBERNETES=https: //$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT TOKEN=`cat /var/run/secrets/kubernetes.io/serviceaccount/token` POD=`hostname` curl -s -k -H "Authorization: Bearer $TOKEN" $KUBERNETES/api/v1/namespaces/$KUBERNETES_NAMESPACE/pods/$POD | grep -i hostIp | cut -d "\"" -f 4 |
Вы можете (2), указав монтирование тома hostDir на Jenkins POD.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
{ "volumeMounts" : [ { "name" : "docker-socket" , "mountPath" : "/var/run/docker.sock" , "readOnly" : false } ], "volumes" : [ { "name" : "docker-socket" , "hostPath" : { "path" : "/var/run/docker.sock" } } ] } |
Фактический пример такой настройки можно найти здесь .
Pros
- Самый простой возможный подход
- Минимальное количество плагинов
Cons
- Не масштабируется
- Прямой доступ к демону Docker
- Требуется доступ к определенным путям на хосте (см. Примечания к Docker Workflow Plugin )
Докер Плагин управляемый Рабы
Предыдущий подход не масштабируется по очевидным причинам. Поскольку Docker и Kubernetes уже существуют, звучит как хорошая идея использовать их в качестве пула ресурсов.
Таким образом, мы можем добавить плагин Docker и заставить его создавать подчиненный контейнер для каждой сборки, которую мы хотим запустить. Это означает, что нам нужен контейнер Docker, который будет иметь доступ к двоичному файлу Docker (требование рабочего процесса Docker ), а также будет монтировать рабочее пространство проекта из мастера.
Как упоминалось выше, мастер должен будет подключиться через ssh к подчиненному. Для этого нужно либо настроить учетные данные, либо соответствующие ключи ssh. В обоих случаях необходимо обновить XML-конфигурацию подключаемого модуля Docker, чтобы ссылаться на идентификатор конфигурации учетных данных Jenkins (например, см. Этот config.xml ) .
Так что же это за идентификатор?
Дженкинс использует плагин Credentials для хранения и получения учетных данных. Каждый набор учетных данных имеет уникальный идентификатор, и другие плагины могут использовать этот идентификатор для ссылки на набор учетных данных. По соображениям безопасности пароли, парольные фразы и т. Д. Не хранятся в виде простого текста, но вместо этого они шифруются с использованием SHA256 . Ключ, который используется для шифрования, также зашифрован, чтобы обеспечить более высокую безопасность. Вы можете найти более подробную информацию по этому вопросу в этом замечательном посте « Хранилище учетных данных в Дженкинсе ».
Я хочу, чтобы вы заметили, что из-за того, как учетные данные хранятся в Jenkins, создание тривиального и подчиненного образа, которые общаются друг с другом, без взаимодействия с человеком, не тривиально. Можно попробовать использовать сценарии, такие как:
1
2
3
4
5
6
7
8
9
|
#Generate master.key and secret MAGIC= "::::MAGIC::::" mkdir -p /var/jenkins_home/secrets openssl rand -hex 128 > /var/jenkins_home/secrets/master.key openssl dgst -sha256 -binary /var/jenkins_home/secrets/master.key > /tmp/master.hashed HEX_MASTER_KEY=`head -c 16 /tmp/master.hashed | xxd -l 16 -p` openssl rand 259 > /tmp/base echo $MAGIC >> /tmp/base openssl enc -aes- 128 -ecb -in /tmp/base -K $HEX_MASTER_KEY -out /var/jenkins_home/secrets/hudson.util.Secret |
Для генерации секрета и мастер-ключа. И чтобы использовать их для шифрования пароля, вы можете использовать такой скрипт:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
#!/bin/bash IN=`echo $ 1 | base64` SUFFIX= "::::MAGIC::::" MASTER_KEY=`cat /var/jenkins_home/secrets/master.key` HASHED_MASTER_KEY=`echo -n $MASTER_KEY | sha256sum | cut -d " " -f 1 ` HASHED_MASTER_KEY_16=${HASHED_MASTER_KEY: 0 : 16 } openssl enc -d -aes- 128 -ecb -in /var/jenkins_home/secrets/hudson.util.Secret -K $HASHED_MASTER_KEY -out /tmp/hudson.key HUDSON_KEY=`cat /tmp/hudson.key` HUDSON_KEY_TRIMMED=${HUDSON_KEY: 0 :- 16 } HUDSON_KEY_16=${HUDSON_KEY_TRIMMED: 0 : 16 } echo $HUDSON_KEY_16 > /tmp/hudson16.key echo "$IN$SUFFIX" > /tmp/jenkins.password openssl enc -aes- 128 -ecb -in /tmp/hudson16.key -out /tmp/jenkins.password.enc -K $IN |
На самом деле шифровать пароли. Я не рекомендовал бы это никому, я просто показываю сценарии, чтобы подчеркнуть, насколько это сложно. Конечно, подобные сценарии также используют детали, встроенные в плагин Credentials, и также немного хакерские. Что я нашел немного более элегантный подход к настройке учетных данных, бросив следующий сценарий groovy внутри Jenkins init.groovy.d:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import jenkins.model.* import com.cloudbees.plugins.credentials.* import com.cloudbees.plugins.credentials.common.* import com.cloudbees.plugins.credentials.domains.* import com.cloudbees.plugins.credentials.impl.* import com.cloudbees.jenkins.plugins.sshcredentials.impl.* import hudson.plugins.sshslaves.*; domain = Domain.global() store = Jenkins.instance.getExtensionList( 'com.cloudbees.plugins.credentials.SystemCredentialsProvider' )[ 0 ].getStore() priveteKey = new BasicSSHUserPrivateKey( CredentialsScope.GLOBAL, "jenkins-slave-key" , "root" , new BasicSSHUserPrivateKey.UsersPrivateKeySource(), "" , "" ) usernameAndPassword = new UsernamePasswordCredentialsImpl( CredentialsScope.GLOBAL, "jenkins-slave-password" , "Jenkis Slave with Password Configuration" , "root" , "jenkins" ) store.addCredentials(domain, priveteKey) store.addCredentials(domain, usernameAndPassword) |
Приведенный выше фрагмент демонстрирует, как создать учетные данные имени пользователя и пароля, а также закрытый ключ SSH с пустой парольной фразой.
Pros
- Достаточно просто
Cons
- Docker Plugin в настоящее время еще не существует?
- Прямой доступ к демону Docker
- Требуется доступ к определенным путям на хосте (см. Примечания к Docker Workflow Plugin )
Даже если мы оставим в стороне проблемы с плагином Docker , я все же хотел бы пойти на подход, который бы напрямую не связывался с демоном Docker , работающим за Kubernetes .
Docker Plugin управляемый Slaves с DIND
Почему нужно использовать Docker в Docker ?
В нашем случае, чтобы не отставать от Кубернетеса назад.
Число возможностей здесь растет. Можно использовать DIND непосредственно на мастере Kubernetes , или можно объединить его с плагином Docker, чтобы каждый раб работал со своим собственным демоном и был на 100% изолирован.
В любом случае, то, что происходит во время сборки, полностью изолировано от остального мира. С другой стороны, это требует использования привилегированного режима. Это может быть проблемой, так как режим может быть недоступен в некоторых средах (то есть он не был доступен в Google Container Engine в прошлый раз, когда я проверял).
Примечание: размещение демона докера в ведомом устройстве освобождает нас от необходимости использовать томовые монтирования на внешнем докере (помните, что для совместного использования рабочего пространства необходим только исполнитель и шаги рабочего процесса).
Pros
- 100% изоляция
- Не требует доступа к определенным путям на внешнем докере!
Cons
- сложность
- Требуется привилегированный режим
- Изображения Docker не «кэшируются»
Использование клиентов Swarm
DIND или нет, еще нужно найти решение для масштабирования, и Docker Plugin до сих пор не кажется идеальным решением. Также эквивалент плагина Docker для Kubernetes ( плагин Kubernetes ) действительно кажется, что он требует немного большего внимания. Итак, мы остались с Роем .
Использование Swarm действительно подходит, так как мы используем Kubernetes и его довольно тривиально для запуска N контейнеров, на которых работает клиент Swarm . Мы могли бы использовать контроллер репликации с соответствующим образом.
Pros
- Быстро
- Масштабируемость
- крепкий
Cons
- Рабы должны управляться извне.
- Требуется доступ к определенным путям на хосте (см. Примечания к Docker Workflow Plugin )
Использование клиентов Swarm с DIND
Основная проблема с DIND в этом случае использования заключается в том, что изображения в «в Docker » не кэшируются. Можно попробовать поэкспериментировать с разделением реестра Docker, но я не уверен, возможно ли это вообще.
С другой стороны, с большинством оставшихся опций нам нужно использовать монтирование hostPath, которое может не работать в некоторых средах.
Решение, которое решает обе вышеупомянутые проблемы, — объединить Swarm с DIND.
С Swarm клиенты остаются (а не стираются после каждой сборки). Это решает проблемы кэширования изображений.
Кроме того, с DIND нам больше не нужно использовать хост-монтирования через Kubernetes.
Так что у нас есть победа — победа.
Pros
- Быстро
- Масштабируемость
- крепкий
- 100% изоляция
- Изображения кешируются
Cons
- Рабы должны управляться извне.
Заключительные мысли
Я устал от всех вышеперечисленных установок как часть документа, который я делал: « Jenkins для Docker Workflow на Kubernetes », и я подумал, что должен поделиться. Есть еще вещи, которые я бы хотел попробовать:
- Используйте секреты для аутентификации рабов.
- Удалить беспорядок
- и т.д
Не стесняйтесь добавлять впечатления, предложения, исправления в комментариях.
Я надеюсь, что вы сочли полезным.
Ссылка: | Настройки Jenkins для Kubernetes и Docker Workflow от нашего партнера JCG Иоанниса Канеллоса в блоге |