LINUX.ORG.RU

CD/CI Pipeline (github, jenkins, docker, k8s)

 , , , ,


1

1

Хочу разобраться как настраивать CD/CI Pipeline по науке, чтобы код из репо github оказался запущенным на kubernetes кластере. Предполагается, что код нужно компилировать. Я уже более-менее во всем разобрался, хочу вынести свои мысли на обсуждение, чтобы понять правильно ли я понял концепцию и не нарушаю ли я какие-то принципы.

И так, сначала грубое представление:
 
1. Скачиваем исходный код с github repo
2. Компилируем и собираем docker image
3. Заливаем этот image на docker repo
4. Разворачиваем pod (или deployment) на k8s кластере из image, который мы залили на docker repo.

Архитектура:
* github repo

* jenkins server
  +docker
  +development tools(для компиляции)
  +kubectl (для управления k8s кластером)

* docker repo (я выбрал AWS ECR)

* k8s cluster

Права доступа, авторизация и т.п.:

1. Из публичного github repo можно брать сырцы свободно, если это private repo, то нужно установить plugin для jenkins, который позволяет авторизовываться по сертификату.

2. Для того, чтобы jenkins мог работать с docker нужно добавить пользователя jenkins в группу docker

3. Для того, чтобы docker мог заливать images на docker repo, нужно приладить скрипт (и awscli), который будет регулярно запрашивать токены у AWS ECR и обновлять их в папке ~/.docker пользователя jenkins.

4. Для того, чтобы jenkins мог управлять k8s кластером, нужно скопировать на сервер бинарник kubectl и добавить файл config с ключами в папку ~/.kube для пользователя jenkins

5. Для того, чтобы k8s cluster мог получать images с docker repo, нужно приладить cronejob, который будет регулярно запрашивать токены у AWS ECR и обновлять у себя secrets авторизации с docker repo.

У меня как-то так получилось, нормально?

don’t build on the master

  1. Для того, чтобы jenkins мог работать с docker нужно добавить пользователя jenkins в группу docker

И тут фактически код, запускаемый Jenkins, получит root права в той системе, где запускается, в том числе доступ к секретам, хранящимся в Jenkins. Поэтому лучше сразу научиться запускать Jenkins slave с нужными тэгами, и в pipeline прописывать как то так:

pipeline {
    agent { label 'docker' }
    options {
        disableConcurrentBuilds()
        timestamps()
    }

Это второй пункт отсюда https://wiki.jenkins.io/display/JENKINS/Jenkins+Best+Practices

In larger systems, don’t build on the master.

LeNiN ()

Компилируем и собираем docker image

По-хорошему докер образ нужно собирать один раз, положив туда рантайм зависимости. А апликуху билдить отдельно, желательно в билд-образе. Иначе у тебя на каждый чих будет по версии докер образа.

P.S. Если выкинуть гитхаб и дженкинс и заменить на гитлаб, то будет проще все настроить. В гитлабе есть и докер регистр и CI/CD пайплайн с поддержкой k8s.

cocucka ()
Ответ на: don’t build on the master от LeNiN

И тут фактически код, запускаемый Jenkins, получит root права в той системе, где запускается, в том числе доступ к секретам, хранящимся в Jenkins.

Спасибо за ответ, т.е. в целях сохранения jenkins секретов, мы можем запускать все работы на ведомых нодах. Допустим я так настроил, но на ведомых нодах тоже будет sensitive data. Например доступ к управлению k8s кластером, мне кажется это будет поважнее, чем секреты хранящиеся в jenkins.

Может тогда нужно еще разделить задачу:

1. Jenkins master скачивает исходный код и передаем его агенту

2. Первый агент компилит код, собирает image и отправляет его в репозиторий.

3. Второй агент или даже мастер, у кого есть доступ к k8s, деплоит приложение в k8s.

Таким образом в процессе компиляции и сборки образа, у агента, который это делает, не будет прав доступа к k8s. Соответственно вредоносный код не сможет туда добраться.

samson_b ()
Последнее исправление: samson_b (всего исправлений: 1)
Ответ на: комментарий от cocucka

По-хорошему докер образ нужно собирать один раз, положив туда рантайм зависимости. А апликуху билдить отдельно, желательно в билд-образе. Иначе у тебя на каждый чих будет по версии докер образа.

В моем тестовом проекте создается два промежуточных образа, в которых все компилируется и потом уже финальный образ собирается путем копирования нужных бинарных файлов из промежуточных образов.

Кстати, хотел спросить по поводу промежуточных образов, чтобы они не накапливались, я прикрутил логику где они процессе создания помечаются метками (label) и потом удаляются:

docker rmi $(docker images -q -f "dangling=true" -f "label=autodelete=$BUILD_ID")

Это нормальный подход?

samson_b ()
Последнее исправление: samson_b (всего исправлений: 1)
Ответ на: комментарий от samson_b

Кстати, хотел спросить по поводу промежуточных образов, чтобы они не накапливались, я прикрутил логику где они процессе создания помечаются метками (label) и потом удаляются:

Специально делаешь, чтобы кеширование не работало?

AnDoR ★★★★★ ()
Ответ на: комментарий от cocucka

По-хорошему докер образ нужно собирать один раз, положив туда рантайм зависимости. А апликуху билдить отдельно, желательно в билд-образе. Иначе у тебя на каждый чих будет по версии докер образа.

Это ж можно сделать в одном Dockerfile через multi-stage build. Последний стейдж — это образ приложения, он будет копировать артефакты приложения из сборочных стейджей, а сам браться из кэша.

theNamelessOne ★★★★★ ()
Ответ на: комментарий от theNamelessOne

Это ж можно сделать в одном Dockerfile через multi-stage build. Последний стейдж — это образ приложения, он будет копировать артефакты приложения из сборочных стейджей, а сам браться из кэша.

В моем случае так и сделано.

samson_b ()