В данном методе используется инструмент werf от компании Флант для сборки и доставки приложения и их накопленные знания конфигураций CI/CD и деплоя приложений в K8s.
Фактический результат
Имеем микросервисную архитектуру в k8s, где крутятся и деплоятся сервисы на пхп, го, js … Под каждый микросервис создается отдельный репозиторий, который содержит помимо исходников кода набор кубернетис ресурсов (deployment, configMap, Secret, Job…)
Проблематика
Выкат и настройка каждого микросервиса становится головной болью, по сути каждый микросервис содержит одинаковые описания ресурсов для k8s (копипаст), нет единого места для изменения ресурсов кубурнетиса для проекта, много лишних знаний об инфроструктуре для программистов, да разработчики бывают разные, кто то может все настроить сам, понимает как это все работает, а кто то нет, по сути такая реализация и была задумана для того чтобы упростить настройку деплоя для разработчиков и девопсов.
Желаемый результат
Иметь единый стандартизированный helm репозиторий (php, go, js …), поддержка семантического версирования чарта, в дочернем проекте иметь только файлы values для определенного окружения с помощью которых настраивать деплой приложения.
Действующие лица
Gitlab, K8s, werf, docker (подразумевается что все доступы к k8s, Gitlab, docker уже имеются)
Поехали!
Werf
Установим werf на сервер Gitlab следуя официальной документации (werf можно использовать без установки на хост запуская image) https://ru.werf.io/documentation/v1.2/index.html?usage=ci&ci=gitlabCiCd&runnerType=hostRunner&os=linux&buildBackend=docker&projectType=simplified&sharedCICD=no&repoType=application
Настроим runner для проекта https://ru.werf.io/documentation/v1.1/guides/gitlab_ci_cd_integration.html
Родительский репозиторий
-
Создаем новый репозиторий laravel-chart, структура файлов
-
.helm/charts/laravel-chart/Chart.yaml
apiVersion: v2 name: laravel-chart description: Laravel chart version: 1.1.1 appVersion: "1.0.0"
-
.gitlab-ci.yaml подробное описание инструкций можно посмотреть в статье
stages: - publish-charts variables: REPO_URL: "${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/packages/helm/api/stable/charts" before_script: - set -eo pipefail - type trdl && . $(trdl use werf 1.2 stable) # Активируем werf для gitlab - type werf && source $(werf ci-env gitlab --as-file) - | werf helm repo update find . -type f -regex '.*/\(Chart.ya?ml\|requirements.ya?ml\)' -exec \ sh -c 'werf helm dependency build $(dirname "{}") --skip-refresh' \; "publish charts": stage: publish-charts script: - | mkdir -p .packages while read chart; do echo "[PACKAGING CHART $chart]" werf helm package "$chart" -d .packages done < <(find .helm/charts -mindepth 1 -maxdepth 1 -type d) - | find .packages -mindepth 1 -maxdepth 1 -type f -name '*.tgz' -exec sh -c 'basename "$0"' '{}' \; | while read package; do CHART_NAME=$(echo $package | sed -e 's/-[0-9]\.[0-9]\.[0-9]\.tgz$//g') CHART_VERSION=$(echo $package | sed -e 's/^[a-zA-Z-].*-//g' | sed -e 's/.tgz$//g') CHART_EXISTS=$(werf helm search repo -l $REPO_NAME/$CHART_NAME | { egrep "$REPO_NAME/$CHART_NAME\s"||true; } | { egrep "$CHART_VERSION\s"||true; } | wc -l) if [ $CHART_EXISTS = 0 ]; then curl -sSl --post301 --form "chart=@.packages/$package" --user "$REPO_PUSH:$REPO_PUSH_SECRET" "$REPO_URL" else echo "Chart package $package already exists in Helm repo! Skip!" fi done only: refs: - master tags: - werf
3. Настроим токены для доступа к родительскому репозиторию, Settings -> Repository -> Deploy tokens,создаём новый токен с правами read_package_registry и write_package_registry
Добавим переменные окружения CI/CD
-
REPO_NAME — laravel-chart
-
REPO_PUSH — название нашего токена который создали выше
-
REPO_PUSH_SECRET — секрет нашего токена который создали выше
-
Заходим на машину где будем запускать наш CI и и регестируем helm repo
werf helm repo add --username $REPO_PUSH --password $REPO_PUSH_SECRET $REPO_NAME ${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/packages/helm/stable werf helm repo update
-
Коммитим и пушим наш чарт в репозиторий, после пуша наш чарт должен появится в
Packages & Registries->Package Registry нашего репозитория
Дочерний репозиторий
1. Создаем новый репозиторий структура файлов

.helm/Chart.yaml
apiVersion: v2 name: laravel version: 1.0.2 dependencies: - name: laravel-chart export-values: - parent: werf child: werf version: ~1.0 repository: "@laravel-chart"
werf.yaml
project: laravel configVersion: 1 --- image: backend dockerfile: deploy.Dockerfile target: backend --- image: frontend dockerfile: deploy.Dockerfile target: frontend
werf-giterminism.yaml (тут мы сознательно отключаем гитерминизм в werf т.к наш чарт не будет находится под гит контролем)
giterminismConfigVersion: 1 helm: allowUncommittedFiles: - ".helm/Chart.lock" - ".helm/charts/*.tgz"
.gitlab-ci.yaml
stages: - publish-chart - build - test - deploy - cleanup variables: REPO_URL: "${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/packages/helm/api/stable/charts" HELM_URL: "${CI_SERVER_URL}/api/v4/projects/${CI_PROJECT_ID}/packages/helm/stable" MAIN_REPO_NAME: "laravel-chart" MAIN_HELM_URL: "${CI_SERVER_URL}/api/v4/projects/{id родительского репозитория}/packages/helm/stable" default: before_script: - set -eo pipefail - type trdl && . $(trdl use werf 1.2 stable) - type werf && source $(werf ci-env gitlab --as-file) - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY Publish Charts: stage: publish-chart script: | werf helm repo add --force-update --username $MAIN_REPO_PULL --password $MAIN_REPO_PULL_SECRET $MAIN_REPO_NAME $MAIN_HELM_URL werf helm repo update werf helm dependency update .helm/ find .helm/charts -mindepth 1 -maxdepth 1 -type f -name '*.tgz' -exec sh -c 'basename "$0"' '{}' \; | while read package; do CHART_NAME=$(echo $package | sed -e 's/-[0-9]\.[0-9]\.[0-9]\.tgz$//g') CHART_VERSION=$(echo $package | sed -e 's/^[a-zA-Z-].*-//g' | sed -e 's/.tgz$//g') CHART_EXISTS=$(werf helm search repo $CI_PROJECT_NAME | { egrep "$MAIN_REPO_NAME/$CHART_NAME\s" || true; } | { egrep "$CHART_VERSION\s" || true; } | wc -l) if [ $CHART_EXISTS = 0 ]; then curl -sSl --post301 --form "chart=@.helm/charts/$package" --user "$CLIENT_REPO_PUSH:$CLIENT_REPO_PUSH_SECRET" "$REPO_URL" else echo "Chart package $package already exists in Helm repo! Skip!" fi done werf helm repo add --username $CLIENT_REPO_PULL --password $CLIENT_REPO_PULL_SECRET $CI_PROJECT_NAME $HELM_URL werf helm repo update only: - development - staging - master tags: [werf] except: [schedules] #подготавливаем образы приложения Build and Publish: stage: build script: - werf build except: [schedules] tags: [werf] only: - development - staging - master #запускаем контейнер, запускаем в нем тесты и после прохождения удаляем его Phpunit: stage: test script: - werf helm dependency update .helm/ - werf converge --skip-build --env testing --values .helm/testing/values.yaml - werf kube-run backend --log-verbose=true --env testing -- vendor/bin/phpunit --colors=never - werf dismiss --env testing --with-namespace only: - development - staging - master environment: name: ${CI_COMMIT_REF_SLUG} tags: [werf] except: [schedules] dependencies: - Build and Publish .base_deploy: stage: deploy tags: [werf] except: [schedules] dependencies: - Build and Publish #деплоим в дев окружение Deploy to development: extends: .base_deploy script: - werf helm dependency update .helm/ - werf converge --skip-build --env development --auto-rollback=true --values .helm/development/values.yaml only: - development environment: name: development #деплоим в стаг окружение Deploy to staging: extends: .base_deploy script: - werf helm dependency update .helm/ - werf converge --skip-build --env staging --auto-rollback=true --values .helm/staging/values.yaml only: - staging environment: name: staging #деплоим в прод окружение Deploy to production: extends: .base_deploy script: - werf helm dependency update .helm/ - werf converge --skip-build --env production --auto-rollback=true --values .helm/production/values.yaml only: - master environment: name: production #запускаем таск для удаления не нужных образов в регистри Cleanup: stage: cleanup script: - werf cr login -u nobody -p ${WERF_IMAGES_CLEANUP_PASSWORD} ${WERF_REPO} - werf cleanup --repo=${WERF_REPO} only: [schedules] tags: [werf]
-
Настроим токены для доступа к репозиторию,
Settings->Repository->Deploy tokens,создаём новые токены-
Первый с правами write_package_registry и помещаем полученные значения в переменные окружения дочернего репозитория CLIENT_REPO_PUSH и CLIENT_REPO_PUSH_SECRET
-
Второй с правами read_package_registry и помещаем полученные значения в переменные окружения дочернего репозиторияCLIENT_REPO_PULL и CLIENT_REPO_PULL_SECRET
-
Переходим в родительский репозиторий в раздел
Settings->Repository->Deploy tokensи создаем токен с правами read_package_registry, помещаем полученные значения в переменные окружения дочернего репозитория MAIN_REPO_PULL и MAIN_REPO_PULL_SECRET
-
В статье не рассматриваются тонкости подготовки образов, настройки CI/CD и деплоя приложения используя werf. Это тема отдельной статьи.
Итог
После всех манипуляций мы имеем возможность настроить наш дочерний репозиторий имея только values в проекте, при запуске CI родительский чарт выкачается и запушится в дочерний package registry, имеем поддержку семантического версирования.
ссылка на оригинал статьи https://habr.com/ru/articles/734922/
Добавить комментарий