GitLab+Helm+GitLab Runner Java-проект CICD практика посадки в среде k8s

Kubernetes

задний план

В настоящее время используется 5 серверов для сборкиKubernetesВ кластерной среде реализованы мониторинг и сбор журналов, а бизнес также вручную перенесен в кластер для бесперебойной работы, поэтому необходимоdockerПроцесс CICD среды перенесен вKubernetesв кластере

Преимущество

KubernetesКластеризация для реализации CICD имеет несколько существенных преимуществ.

  1. DeploymentЕстественная поддержка непрерывного развертывания в сочетании с другимиKubernetesФункции также могут обеспечить сине-зеленое развертывание, канареечное развертывание и т. д.
  2. новая версияGitLabиGitLab Runnerестественная поддержкаKubernetesкластер, поддержкаrunnerАвтоматическое масштабирование для сокращения использования ресурсов

окрестности

KubernetesВерсия: 1.14

GitLabВерсия: 12.2.5

GitLab-RunnerВерсия: 12.1.0

DockerВерсия среды: 17.03.1

Развертывание GitLab-Runner

Введение в конфигурацию

исходная средаgitlab runnerВыполняя вручную команду регистрации и команду запуска, предоставленную на официальном веб-сайте, он делится на два развертывания, что требует большего количества ручных операций.Kubernetes, который поддерживает использованиеHelmРазвертывание в один клик, официальные документы следующие

GitLab Runner Helm Chart

На самом деле, рекомендации официальной документации не ясны, и многие конфигурации не представлены в документации.Рекомендуется перейти в репозиторий исходного кода, чтобы просмотреть подробную документацию по использованию параметров.

The Kubernetes executor

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

Сборка с DinD больше не рекомендуется

официальная документациявводить

Use docker-in-docker workflow with Docker executor

The second approach is to use the special docker-in-docker (dind) Docker image with all tools installed (docker) and run the job script in context of that image in privileged mode.

Note: docker-compose is not part of docker-in-docker (dind). To use docker-compose in your CI builds, follow the docker-compose installation instructions.

Danger: By enabling --docker-privileged, you are effectively disabling all of the security mechanisms of containers and exposing your host to privilege escalation which can lead to container breakout. For more information, check out the official Docker documentation on Runtime privilege and Linux capabilities.

Docker-in-Docker works well, and is the recommended configuration, but it is not without its own challenges:

  • При использовании docker-in-docker каждое задание находится в чистой среде без прошлой истории. Параллельные задания работают нормально, потому что каждая сборка получает собственный экземпляр механизма Docker, поэтому они не будут конфликтовать друг с другом. Но это также означает, что задания могут быть медленнее, потому что нет кэширования слоев.
  • By default, Docker 17.09 and higher uses --storage-driver overlay2 which is the recommended storage driver. See Using the overlayfs driver for details.
  • Since the docker:19.03.1-dindконтейнер и контейнер Runner не используют общую корневую файловую систему, рабочий каталог задания можно использовать в качестве точки монтирования для дочерних контейнеров.Например, если у вас есть файлы, которыми вы хотите поделиться с дочерним контейнером, вы можете создать подкаталог в/builds/$CI_PROJECT_PATH and use it as your mount point (for a more thorough explanation, check issue #41227):

В любом случае используйтеDinDВыполнение сборки контейнеров возможно, но сталкивается со многими проблемами, такими как использованиеoverlay2Для работы в сети требуется версия Docker выше 17.09.

Using docker:dind

Running the docker:dind also known as the docker-in-docker image is also possible but sadly needs the containers to be run in privileged mode. If you're willing to take that risk other problems will arise that might not seem as straight forward at first glance. Because the docker daemon is started as a service usually in your .gitlab-ci.yaml it will be run as a separate container in your Pod. Basically containers in Pods only share volumes assigned to them and an IP address by which they can reach each other using localhost. /var/run/docker.sock is not shared by the docker:dind container and the docker binary tries to use it by default.

To overwrite this and make the client use TCP to contact the Docker daemon, in the other container, be sure to include the environment variables of the build container:

  • DOCKER_HOST=tcp://localhost:2375 for no TLS connection.
  • DOCKER_HOST=tcp://localhost:2376 for TLS connection.

Make sure to configure those properly. As of Docker 19.03, TLS is enabled by default but it requires mapping certificates to your client. You can enable non-TLS connection for DIND or mount certificates as described in Use Docker In Docker Workflow wiht Docker executor

Включено по умолчанию после Docker 19.03.1TLSКонфигурация, ее необходимо объявить во встроенной переменной окружения, иначе сообщение о подключении невозможноdockerошибка и используйтеDinDсоздавать потребностиrunnerВключите привилегированный режим для доступа к ресурсам хоста, а так как привилегированный режим используется, вPodсредняя параrunnerОграничение ресурсов, которое необходимо использовать, будет недействительным.

1574777453616

Создание образов Docker с помощью Kaniko

В настоящее время официально предусмотрен другой метод вdockerСоздавайте и отправляйте образы в контейнер, который является более элегантным и может обеспечить плавную миграцию, т.е.kaniko

Building a Docker image with kaniko

Его преимущества описаны на официальном сайте следующим образом.

Другой способ создать образ Docker в кластере Kubernetes — использоватьkaniko. икоко

  • Позволяет создавать образы без привилегированного доступа.
  • Работает без демона Docker.

В следующей практике для сборки образов Docker будут использоваться два метода, которые можно выбрать в соответствии с реальной ситуацией.

Развертывание с помощью Helm

ВытащитьHelm Gitlab-RunnerСклад на локальный, изменить конфигурацию

GitLab Runner

поставь оригиналgitlab-runnerКонфигурация перенесена вHelm, после миграции следующим образом

image: alpine-v12.1.0
imagePullPolicy: IfNotPresent
gitlabUrl: https://gitlab.fjy8018.top/
runnerRegistrationToken: "ZXhpuj4Dxmx2tpxW9Kdr"
unregisterRunners: true
terminationGracePeriodSeconds: 3600
concurrent: 10
checkInterval: 30
rbac:
  create: true
  clusterWideAccess: false
metrics:
  enabled: true
  listenPort: 9090
runners:
  image: ubuntu:16.04
  imagePullSecrets:
    - name: registry-secret
  locked: false
  tags: "k8s"
  runUntagged: true
  privileged: true
  pollTimeout: 180
  outputLimit: 4096
  cache: {}
  builds: {}
  services: {}
  helpers: {}
resources:
   limits:
     memory: 2048Mi
     cpu: 1500m
   requests:
     memory: 128Mi
     cpu: 200m
affinity: {}
nodeSelector: {}
tolerations: []
hostAliases:
   - ip: "192.168.1.13"
     hostnames:
     - "gitlab.fjy8018.top"
   - ip: "192.168.1.30"
     hostnames:
     - "harbor.fjy8018.top"
podAnnotations: {}

Который настроен с закрытым ключом, интранетharborадрес,harborИзвлечь закрытый ключ ресурса, политика ограничения ресурсов

Выбор GitLab-Runner может привести к ямам

выберитеrunnerзеркально какalpine-v12.1.0, только этот момент, последняя версия бегуна 12.5.0, но в ней много проблем,alpineНовая версия зеркала находится вKubernetesПроизошло прерывание, которое не удалось разрешитьDNSпроблема, отраженная вGitLab-Runnerв центреCould not resolve hostиserver misbehaving

1574778107416

1574778146693

Ознакомьтесь с решением

1574777890021

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

Официальный гитлаб:Kubernetes runner: Could not resolve host

переполнение стека:Gitlab Runner is not able to resolve DNS of Gitlab Server

Приведенные решения без исключения относятся к переходу на alpine-v12.1.0.

We had same issue for couple of days. We tried change CoreDNS config, move runners to different k8s cluster and so on. Finally today i checked my personal runner and found that i'm using different version. Runners in cluster had gitlab/gitlab-runner:alpine-v12.3.0, when mine had gitlab/gitlab-runner:alpine-v12.0.1. We added line

image: gitlab/gitlab-runner:alpine-v12.1.0

in values.yaml and this solved problem for us

Корень проблемы должен быть в том, что у базового образа alpine проблема с поддержкой кластера Kubernetes.

ndots breaks DNS resolving #64924

1574778408166

1574778416868

docker-alpineИмеются также незакрытые соответствующие складыissue, в котором упоминается оDNSПроблемы с разбором тайм-аутов и исключений

DNS Issue #255

1574778470283

Установить

Однострочная команда для установки

$ helm install /root/gitlab-runner/ --name k8s-gitlab-runner --namespace gitlab-runner

Вывод выглядит следующим образом

NAME:   k8s-gitlab-runner
LAST DEPLOYED: Tue Nov 26 21:51:57 2019
NAMESPACE: gitlab-runner
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                             DATA  AGE
k8s-gitlab-runner-gitlab-runner  5     0s

==> v1/Deployment
NAME                             READY  UP-TO-DATE  AVAILABLE  AGE
k8s-gitlab-runner-gitlab-runner  0/1    1           0          0s

==> v1/Pod(related)
NAME                                              READY  STATUS   RESTARTS  AGE
k8s-gitlab-runner-gitlab-runner-744d598997-xwh92  0/1    Pending  0         0s

==> v1/Role
NAME                             AGE
k8s-gitlab-runner-gitlab-runner  0s

==> v1/RoleBinding
NAME                             AGE
k8s-gitlab-runner-gitlab-runner  0s

==> v1/Secret
NAME                             TYPE    DATA  AGE
k8s-gitlab-runner-gitlab-runner  Opaque  2     0s

==> v1/ServiceAccount
NAME                             SECRETS  AGE
k8s-gitlab-runner-gitlab-runner  1        0s


NOTES:

Your GitLab Runner should now be registered against the GitLab instance reachable at: "https://gitlab.fjy8018.top/"

Проверьте страницу администратора gitlab и обнаружите, что бегун был успешно зарегистрирован.

1574778634857

Инженерная конфигурация

DinD способ сборки необходимой конфигурации

Если оригиналciфайл основан на19.03 DinDЗеркальные сборки должны быть добавленыTLSСвязанная конфигурация

image: docker:19.03

variables:
  DOCKER_DRIVER: overlay
  DOCKER_HOST: tcp://localhost:2375
  DOCKER_TLS_CERTDIR: ""
...

Остальная конфигурация остается прежней, построена с помощью DinD.

Конфигурация разрешений Kubectl и Kubernetes

из-за использованияk8sкластер, а развертывание через кластер требует использованияkubectlклиент, поэтому вручную создалkubectl dockerзеркало, использоватьgitlabкурокdockerhubКонструкция, содержимое конструкции открыто и прозрачно, и его можно использовать с уверенностью.Если есть другие версии требований к конструкции, вы также можете отправить запрос на вытягивание, который будет добавлен позже.В настоящее время используется только 1.14.0.

fjy8018/kubectl

1574778835433

имеютkubectlКлиент, также необходимо настроить подключениеTLSи связанные аккаунты

Для обеспечения безопасности создайте новый, который специально обращается к пространству имен проекта.ServiceAccount

apiVersion: v1
kind: ServiceAccount
metadata:
  name: hmdt-gitlab-ci
  namespace: hmdt

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

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
  name: hmdt-gitlab-role
  namespace: hmdt
subjects:
  - kind: ServiceAccount
    name: hmdt-gitlab-ci
    namespace: hmdt
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: admin

После создания запросите его уникальное имя, сгенерированное в кластере k8s, вотhmdt-gitlab-ci-token-86n89

$ kubectl describe sa hmdt-gitlab-ci -n hmdt
Name:                hmdt-gitlab-ci
Namespace:           hmdt
Labels:              <none>
Annotations:         kubectl.`Kubernetes`.io/last-applied-configuration:
                       {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"hmdt-gitlab-ci","namespace":"hmdt"}}
Image pull secrets:  <none>
Mountable secrets:   hmdt-gitlab-ci-token-86n89
Tokens:              hmdt-gitlab-ci-token-86n89
Events:              <none>

Затем найдите сертификат ЦС в соответствии с приведенным выше секретом.

$ kubectl get secret hmdt-gitlab-ci-token-86n89 -n hmdt -o json | jq -r '.data["ca.crt"]' | base64 -d

Затем найдите соответствующий токен

$ kubectl get secret hmdt-gitlab-ci-token-86n89  -n hmdt -o json | jq -r '.data.token' | base64 -d

Конфигурация GitLab, связанная с Kubernetes

Войдите на страницу конфигурации кластера gitlab Kubernetes, заполните соответствующую информацию и разрешите gitlab автоматически подключаться к среде кластера.

1574779375430

1574779403873

Обратите внимание, что вам нужно снять этот флажок, иначе gitlab автоматически создаст новую учетную запись пользователя вместо использования уже созданной учетной записи пользователя и не сообщит об ошибке разрешения во время работы.

1574779467185

Ошибка, вызванная отказом от отмены, выглядит следующим образом: gitlab создал новую учетную запись пользователя.hmdt-prod-service-account, но не имеет разрешения на работу с указанным пространством имен

1574779599949

Конфигурация среды GitLab

Создайте среду

image-20191127095307604

Имя и URL-адрес можно настроить по мере необходимости.

image-20191127095330949

Конфигурация CI-скрипта

Окончательный файл конфигурации CI выглядит следующим образом, в котором используетсяDinDспособ построитьDockerfile

image: docker:19.03

variables:
  MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode -Dmaven.test.skip=true"
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  DOCKER_DRIVER: overlay
  DOCKER_HOST: tcp://localhost:2375
  DOCKER_TLS_CERTDIR: ""
  SPRING_PROFILES_ACTIVE: docker
  IMAGE_VERSION: "1.8.6"
  DOCKER_REGISTRY_MIRROR: "https://XXX.mirror.aliyuncs.com"

stages:
  - test
  - package
  - review
  - deploy

maven-build:
  image: maven:3-jdk-8
  stage: test
  retry: 2
  script:
    - mvn $MAVEN_CLI_OPTS clean package -U -B -T 2C
  artifacts:
    expire_in: 1 week
    paths:
      - target/*.jar

maven-scan:
  stage: test
  retry: 2
  image: maven:3-jdk-8
  script:
    - mvn $MAVEN_CLI_OPTS verify sonar:sonar

maven-deploy:
  stage: deploy
  retry: 2
  image: maven:3-jdk-8
  script:
    - mvn $MAVEN_CLI_OPTS deploy

docker-harbor-build:
  image: docker:19.03
  stage: package
  retry: 2
  services:
    - name: docker:19.03-dind
      alias: docker
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE:$IMAGE_VERSION" .
    - docker push "$CI_REGISTRY_IMAGE:$IMAGE_VERSION"
    - docker logout $CI_REGISTRY

deploy_live:
  image: fjy8018/kubectl:v1.14.0
  stage: deploy
  retry: 2
  environment:
    name: prod
    url: https://XXXX
  script:
    - kubectl version
    - kubectl get pods -n hmdt
    - cd manifests/
    - sed -i "s/__IMAGE_VERSION_SLUG__/${IMAGE_VERSION}/" deployment.yaml
    - kubectl apply -f deployment.yaml
    - kubectl rollout status -f deployment.yaml
    - kubectl get pods -n hmdt

Используйте при необходимостиKanikoПостроитьDockerfile, конфигурация следующая

Обратите внимание, что зеркала, которые зависят от нихgcr.io/kaniko-project/executor:debugОн принадлежит зеркальному складу Google и может быть недоступен.

image: docker:19.03

variables:
  MAVEN_CLI_OPTS: "-s .m2/settings.xml --batch-mode -Dmaven.test.skip=true"
  MAVEN_OPTS: "-Dmaven.repo.local=.m2/repository"
  DOCKER_DRIVER: overlay
  DOCKER_HOST: tcp://localhost:2375
  DOCKER_TLS_CERTDIR: ""
  SPRING_PROFILES_ACTIVE: docker
  IMAGE_VERSION: "1.8.6"
  DOCKER_REGISTRY_MIRROR: "https://XXX.mirror.aliyuncs.com"

cache:
  paths:
    - target/

stages:
  - test
  - package
  - review
  - deploy

maven-build:
  image: maven:3-jdk-8
  stage: test
  retry: 2
  script:
    - mvn $MAVEN_CLI_OPTS clean package -U -B -T 2C
  artifacts:
    expire_in: 1 week
    paths:
      - target/*.jar

maven-scan:
  stage: test
  retry: 2
  image: maven:3-jdk-8
  script:
    - mvn $MAVEN_CLI_OPTS verify sonar:sonar

maven-deploy:
  stage: deploy
  retry: 2
  image: maven:3-jdk-8
  script:
    - mvn $MAVEN_CLI_OPTS deploy


docker-harbor-build:
  stage: package
  retry: 2
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$IMAGE_VERSION

deploy_live:
  image: fjy8018/kubectl:v1.14.0
  stage: deploy
  retry: 2
  environment:
    name: prod
    url: https://XXXX
  script:
    - kubectl version
    - kubectl get pods -n hmdt
    - cd manifests/
    - sed -i "s/__IMAGE_VERSION_SLUG__/${IMAGE_VERSION}/" deployment.yaml
    - kubectl apply -f deployment.yaml
    - kubectl rollout status -f deployment.yaml
    - kubectl get pods -n hmdt

конвейер выполнения

бегун автоматически расширяется и сжимается

KubernetesБегун в раннере будет автоматически расширяться и сжиматься в зависимости от количества задач Текущее ограничение конфигурации — 10.

1574776369212

Grafana также может отслеживать использование ресурсов кластера в процессе сборки.

1574776599795

использоватьDinDПостроитьDockerfileрезультат

image-20191127100525518

использоватьKanikoПостроитьDockerfileрезультат

image-20191127100458620

Результат развертывания

При развертывании gitlab автоматически внедрит настроенную конфигурацию.kubectl config

image-20191127095832650

построить результат

image-20191127095739561

После завершения развертывания вы можете просмотреть результаты развертывания на странице конфигурации среды.Будут записаны только успешные развертывания.

image-20191127095923676