Заметки Kubernetes (3): Gitlab+Jenkins Pipeline+Docker+k8s+Helm Automated Deployment Practice (совместное использование сухих товаров!)

Kubernetes

В предыдущих двух статьях у нас уже есть кластерная среда K8s, которая «ждет загрузки», и у нас также есть базовое понимание связанных концепций и компонентов (вы можете получить представление о концепциях на ранней стадии, потому что только практики, может у вас есть глубокое понимание этого. Поймите, так называемое «на бумаге это мелко, и вы должны знать, что вы должны это сделать»), эта статья знакомит с практической точки зрения, как объединить наши обычно используемые Gitlab и Jenkins для автоматического развертывания проектов через K8s, примеры будут включать серверные проекты на основе SpringBoot и веб-проекты на основе Vue.js.

Инструменты и методы, описанные в этой статье, включают в себя:

  • Gitlab — широко используемая система управления исходным кодом
  • Jenkins, Jenkins Pipeline — широко используемый инструмент автоматизированной сборки и развертывания, Pipeline организует различные этапы построения и развертывания конвейерным способом.
  • Docker, Dockerfile — контейнерный движок, все приложения в конечном итоге будут работать как контейнеры Docker, Dockerfile — это файл определения образа Docker.
  • Kubernetes — система управления оркестрацией контейнеров с открытым исходным кодом от Google.
  • Helm — инструмент управления пакетами Kubernetes, аналогичный Linux yum, apt или Node npm и другим инструментам управления пакетами, может организовывать и управлять приложениями и связанными зависимыми службами в Kubernetes в виде пакетов (диаграмма)

Экологический фон:

  1. Gitlab использовался для управления исходным кодом.Исходный код имеет разработанные (соответствующие среде разработки), предварительные версии (соответствующие тестовой среде) и основные (соответствующие производственной среде) ветки в соответствии с различными средами.
  2. Служба Jenkins была построена
  3. Существующая служба Docker Registry для хранения образов Docker (на основе Docker Registry или Harbour, созданных самостоятельно, или с использованием облачных служб, в этой статье используется служба образов облачных контейнеров Alibaba)
  4. Кластер K8s построен

ожидаемый результат:

  1. Развертывайте приложения в разных средах, разделяйте среду разработки, тестовую среду и производственную среду и развертывайте их в разных пространствах имен одного и того же кластера или в разных кластерах (например, разработка и тестирование развертываются в разных пространствах имен локального кластера, а производственная среда развернута в облачном кластере)
  2. Конфигурация является максимально общей, и автоматическую настройку развертывания нового проекта можно выполнить, только изменив небольшое количество свойств конфигурации в небольшом количестве файлов конфигурации.
  3. Среда разработки и тестирования автоматически запускает сборку и развертывание при отправке кода, а производственная среда добавляет тег версии в основную ветку и запускает автоматическое развертывание после тега push.
  4. Общий процесс взаимодействия выглядит следующим образом

jenkins-cicd

файл конфигурации проекта

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

springboot-ci-structure

включают:

  1. Dockerfile, файл, используемый для создания образа Docker (ссылкаПримечания к Docker (11): Подробное объяснение файла Docker и рекомендации)
  2. Файлы конфигурации, связанные с Helm. Helm — это инструмент управления пакетами для Kubernetes, который может упаковывать развертывание, сервис, вход и т. д., связанные с развертыванием приложения для выпуска и управления (конкретное введение Helm будет добавлено позже)
  3. Jenkinsfile, файл определения конвейера Jenkins, определяет задачи, которые должны выполняться на каждом этапе.

Dockerfile

Добавьте Dockerfile (имя файла называется Dockerfile) в корневой каталог проекта, чтобы определить, как создавать образ Docker.В качестве примера возьмем проект Spring Boot,

FROM frolvlad/alpine-java:jdk8-slim
#在build镜像时可以通过 --build-args profile=xxx 进行修改
ARG profile
ENV SPRING_PROFILES_ACTIVE=${profile}
#项目的端口
EXPOSE 8000 
WORKDIR /mnt

#修改时区
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
    && apk add --no-cache tzdata \
    && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && apk del tzdata \
    && rm -rf /var/cache/apk/* /tmp/* /var/tmp/* $HOME/.cache

COPY ./target/your-project-name-1.0-SNAPSHOT.jar ./app.jar
ENTRYPOINT ["java", "-jar", "/mnt/app.jar"]

Предоставьте SPRING_PROFILES_ACTIVE через профиль параметров, который можно динамически установить во время сборки с помощью --build-args profile=xxx, чтобы удовлетворить требования построения образа в различных средах.

SPRING_PROFILES_ACTIVE мог быть передан при запуске контейнера Docker.docker run -e SPRING_PROFILES_ACTIVE=xxxустановить, поэтому развертывание с помощью Helm напрямую не проходитdocker runзапустить, поэтому укажите через ARG во время сборки образа

Конфигурационный файл шлема

Helm — это инструмент управления пакетами для Kubernetes, который упаковывает Deployment, Service и Ingress, связанные с развертыванием приложений для выпуска и управления (которые могут храниться в хранилище, подобно образу Docker). Как показано на рисунке выше, файл конфигурации Helm включает в себя:

helm                                    - chart包的目录名
├── templates                           - k8s配置模版目录
│   ├── deployment.yaml                 - Deployment配置模板,定义如何部署Pod
│   ├── _helpers.tpl                    - 以下划线开头的文件,helm视为公共库定义文件,用于定义通用的子模版、函数、变量等
│   ├── ingress.yaml                    - Ingress配置模板,定义外部如何访问Pod提供的服务,类似于Nginx的域名路径配置
│   ├── NOTES.txt                       - chart包的帮助信息文件,执行helm install命令成功后会输出这个文件的内容
│   └── service.yaml                    - Service配置模板,配置访问Pod的服务抽象,有NodePort与ClusterIp等
|── values.yaml                         - chart包的参数配置文件,各模版文件可以引用这里的参数
├── Chart.yaml                          - chart定义,可以定义chart的名字,版本号等信息
├── charts                              - 依赖的子包目录,里面可以包含多个依赖的chart包,一般不存在依赖,我这里将其删除了

Мы можем определить имя диаграммы каждого проекта (аналогично имени установочного пакета) в Chart.yaml, например

apiVersion: v2
name: your-chart-name
description: A Helm chart for Kubernetes

type: application
version: 1.0.0
appVersion: 1.16.0

Определите переменные, которые необходимо использовать в файле шаблона в values.yaml, например

#部署Pod的副本数,即运行多少个容器
replicaCount: 1
#容器镜像配置
image:
  repository: registry.cn-hangzhou.aliyuncs.com/demo/demo
  pullPolicy: Always
  # Overrides the image tag whose default is the chart version.
  tag: "dev"
#镜像仓库访问凭证
imagePullSecrets:
  - name: aliyun-registry-secret
#覆盖启动容器名称
nameOverride: ""
fullnameOverride: ""
#容器的端口暴露及环境变量配置
container:
  port: 8000
  env: []
#ServiceAccount,默认不创建
serviceAccount:
  # Specifies whether a service account should be created
  create: false
  # Annotations to add to the service account
  annotations: {}
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000
#使用NodePort的service,默认为ClusterIp
service:
  type: NodePort
  port: 8000
#外部访问Ingress配置,需要配置hosts部分
ingress:
  enabled: true
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: demo.com
      paths: ["/demo"]
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

  #.... 省略了其它默认参数配置

Здесь контейнерная часть добавлена ​​на основе дефолтной генерации, здесь можно указать номер порта контейнера без изменения файла шаблона (чтобы файл шаблона был общим в каждом проекте, и обычно его не нужно менять) , В то же время добавьте конфигурацию env, которую можно найти в При развертывании helm переменные среды передаются в контейнер. Тип службы изменен с ClusterIp по умолчанию на NodePort. При развертывании разных проектов одного и того же типа вам нужно всего лишь настроить несколько элементов конфигурации в файлах Chart.yaml и values.yaml в соответствии с ситуацией в проекте.Файлы шаблонов в каталоге templates можно напрямую использовать повторно.

При развертывании вам необходимо извлечь образ из репозитория образов Docker в среде K8s, поэтому вам необходимо создать учетные данные для доступа к репозиторию образов (imagePullSecrets) в K8s.

# 登录Docker Registry生成/root/.docker/config.json文件
sudo docker login --username=your-username registry.cn-shenzhen.aliyuncs.com
# 创建namespace develop(我这里是根据项目的环境分支名称建立namespace)
kubectl create namespace develop
# 在namespace develop中创建一个secret
kubectl create secret generic aliyun-registry-secret --from-file=.dockerconfigjson=/root/.docker/config.json  --type=kubernetes.io/dockerconfigjson --namespace=develop

Jenkinsfile

Jenkinsfile — это файл конфигурации конвейера Jenkins, который следует синтаксису Groovy.Для создания и развертывания проектов Spring Boot напишите файл сценария Jenkinsfile следующим образом:

image_tag = "default"  //定一个全局变量,存储Docker镜像的tag(版本)
pipeline {
    agent any
    environment {
        GIT_REPO = "${env.gitlabSourceRepoName}"  //从Jenkins Gitlab插件中获取Git项目的名称
        GIT_BRANCH = "${env.gitlabTargetBranch}"  //项目的分支
        GIT_TAG = sh(returnStdout: true,script: 'git describe --tags --always').trim()  //commit id或tag名称
        DOCKER_REGISTER_CREDS = credentials('aliyun-docker-repo-creds') //docker registry凭证
        KUBE_CONFIG_LOCAL = credentials('local-k8s-kube-config')  //开发测试环境的kube凭证
        KUBE_CONFIG_PROD = "" //credentials('prod-k8s-kube-config') //生产环境的kube凭证

        DOCKER_REGISTRY = "registry.cn-hangzhou.aliyuncs.com" //Docker仓库地址
        DOCKER_NAMESPACE = "your-namespace"  //命名空间
        DOCKER_IMAGE = "${DOCKER_REGISTRY}/${DOCKER_NAMESPACE}/${GIT_REPO}" //Docker镜像地址

        INGRESS_HOST_DEV = "dev.your-site.com"    //开发环境的域名
        INGRESS_HOST_TEST = "test.your-site.com"  //测试环境的域名
        INGRESS_HOST_PROD = "prod.your-site.com"  //生产环境的域名
    }
    parameters {
        string(name: 'ingress_path', defaultValue: '/your-path', description: '服务上下文路径')
        string(name: 'replica_count', defaultValue: '1', description: '容器副本数量')
    }

    stages {
        stage('Code Analyze') {
            agent any
            steps {
               echo "1. 代码静态检查"
            }
        }
        stage('Maven Build') {
            agent {
                docker {
                    image 'maven:3-jdk-8-alpine'
                    args '-v $HOME/.m2:/root/.m2'
                }
            }
            steps {
                echo "2. 代码编译打包"
                sh 'mvn clean package -Dfile.encoding=UTF-8 -DskipTests=true'
            }
        }
        stage('Docker Build') {
            agent any
            steps {
                echo "3. 构建Docker镜像"
                echo "镜像地址: ${DOCKER_IMAGE}"
                //登录Docker仓库
                sh "sudo docker login -u ${DOCKER_REGISTER_CREDS_USR} -p ${DOCKER_REGISTER_CREDS_PSW} ${DOCKER_REGISTRY}"
                script {
                    def profile = "dev"
                    if (env.gitlabTargetBranch == "develop") {
                        image_tag = "dev." + env.GIT_TAG
                    } else if (env.gitlabTargetBranch == "pre-release") {
                        image_tag = "test." + env.GIT_TAG
                        profile = "test"
                    } else if (env.gitlabTargetBranch == "master"){
                        // master分支则直接使用Tag
                        image_tag = env.GIT_TAG
                        profile = "prod"
                    }
                    //通过--build-arg将profile进行设置,以区分不同环境进行镜像构建
                    sh "docker build  --build-arg profile=${profile} -t ${DOCKER_IMAGE}:${image_tag} ."
                    sh "sudo docker push ${DOCKER_IMAGE}:${image_tag}"
                    sh "docker rmi ${DOCKER_IMAGE}:${image_tag}"
                }
            }
        }
        stage('Helm Deploy') {
            agent {
                docker {
                    image 'lwolf/helm-kubectl-docker'
                    args '-u root:root'
                }
            }
            steps {
                echo "4. 部署到K8s"
                sh "mkdir -p /root/.kube"
                script {
                    def kube_config = env.KUBE_CONFIG_LOCAL
                    def ingress_host = env.INGRESS_HOST_DEV
                    if (env.gitlabTargetBranch == "pre-release") {
                        ingress_host = env.INGRESS_HOST_TEST
                    } else if (env.gitlabTargetBranch == "master"){
                        ingress_host = env.INGRESS_HOST_PROD
                        kube_config = env.KUBE_CONFIG_PROD
                    }
                    sh "echo ${kube_config} | base64 -d > /root/.kube/config"
                    //根据不同环境将服务部署到不同的namespace下,这里使用分支名称
                    sh "helm upgrade -i --namespace=${env.gitlabTargetBranch} --set replicaCount=${params.replica_count} --set image.repository=${DOCKER_IMAGE} --set image.tag=${image_tag} --set nameOverride=${GIT_REPO} --set ingress.hosts[0].host=${ingress_host} --set ingress.hosts[0].paths={${params.ingress_path}} ${GIT_REPO} ./helm/"
                }
            }
        }
    }
}

Jenkinsfile определяет весь автоматизированный процесс сборки и развертывания:

  1. Анализ кода, вы можете использовать инструменты статического анализа кода, такие как SonarQube, для завершения проверки кода, которая здесь игнорируется.
  2. Maven Build, запустите контейнер Maven Docker для завершения сборки и упаковки проекта maven, подключите каталог локального хранилища maven к хост-компьютеру и избегайте необходимости каждый раз повторно загружать пакет зависимостей.
  3. Docker Сборка, сборка образа Docker и отправка его в репозиторий образов Образы в разных средах различаются тегами Среда разработки использует форму dev.commitId, например dev.88f5822, тестовая среда использует test.commitId и производственная среда может установить событие веб-перехватчика для тега push-события, использовать имя тега напрямую
  4. Helm Развертывание, используйте helm для развертывания новых проектов или обновления существующих проектов.В разных средах используются разные конфигурации параметров, такие как имя домена доступа, учетные данные доступа к кластеру K8s kube_config и т. д.

Конфигурация Дженкинса

Конфигурация задачи Дженкинса

Создайте конвейерную задачу в Jenkins, как показано на рисунке

jenkins-pipeline-pro

Настройте триггер сборки, установите целевую ветку на ветку разработки и сгенерируйте токен, как показано на рисунке.

jenkins-pipeline-config1

Запишите здесь «URL-адрес веб-перехватчика GitLab» и значение токена и используйте его в конфигурации Gitlab.

Настройте конвейер, выберите «Сценарий конвейера из SCM», чтобы получить файл сценария конвейера из исходного кода проекта, настройте адрес Git проекта, получите сертификат исходного кода и т. д., как показано на рисунке.

jenkins-pipeline-config2.png

Сохраните, чтобы завершить настройку Jenkins среды разработки проекта. В тестовой среде нужно только изменить соответствующую ветку на предварительную версию.

Конфигурация учетных данных Дженкинса

В Jenkinsfile мы используем два учетных данных для доступа — учетные данные Docker Registry и локальные учетные данные K8s kube,

DOCKER_REGISTER_CREDS = credentials('aliyun-docker-repo-creds') //docker registry凭证
KUBE_CONFIG_LOCAL = credentials('local-k8s-kube-config')  //开发测试环境的kube凭证

Эти два учетных данных должны быть созданы в Jenkins.

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

jenkins-cred

jenkins-cred2

Добавьте учетные данные для доступа к кластеру K8s и закодируйте в base64 содержимое файла /root/.kube/config на главном узле.

base64 /root/.kube/config > kube-config-base64.txt
cat kube-config-base64.txt

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

jenkins-cred3

Введите содержимое в кодировке base64 в текстовое поле «Секрет».

Конфигурация гитлаба

Настройте веб-перехватчик на странице «Настройки — Интеграция» проекта Gitlab, заполните «URL-адрес веб-перехватчика GitLab» и значение токена в предыдущем разделе триггера Jenkins в URL-адресе и секретном токене и выберите «События push» в качестве события триггера, как показано на рисунке

gitlab-webhook-config

Если вы выберете «Отправлять события» для сред разработки и тестирования, когда разработчики отправляют код или объединяют код для разработки или предварительного выпуска ветвей, задача конвейера Jenkins в среде разработки или тестирования будет запущена для завершения автоматической сборки; для рабочей среды среде выберите «События отправки тегов» », чтобы запустить автоматическую сборку при отправке тега push в основную ветку. На рисунке показан вид конструкции трубопровода.

jenkins-build

Суммировать

В этой статье рассказывается об использовании Gitlab+Jenkins Pipeline+Docker+Kubernetes+Helm для реализации автоматического развертывания проектов Spring Boot, которые можно применить к другим проектам на основе Spring Boot с небольшой модификацией (конкретная модификация объясняется в файле Readme). файл исходного кода).

Все конфигурационные файлы, задействованные в этой статье (включая серверные проекты на основе Spring Boot и веб-проекты на основе Vue.js), можно получить в проекте исходного кода (метод получения адреса исходного кода: обратите внимание на официальный аккаунт «Halfway Песня дождя», введите «k8sops» на главной странице (ок).

Оригинальный адрес:blog.J boost.cai/ke 8 — это 3-Chengdu.htm…


Автор: Юге, ветеран ИТ, который все еще учится. Добро пожаловать, чтобы обратить внимание на официальный аккаунт автора: песня Halfway Rain, учитесь и растите вместе
qrcode