NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

每天部署数千个容器实例,扩缩容复杂性该如何管理?

  • 2020-12-29
  • 本文字数:6048 字

    阅读完需:约 20 分钟

每天部署数千个容器实例,扩缩容复杂性该如何管理?

无论是大型软件公司还是小型软件公司,现在每天都要部署数千个容器实例,这种扩缩容的复杂性是他们必须要管理的。本文介绍了如何将 Kubernetes 纳入到现有的传统 CI/CD 管道中,并实现服务的高可用性,以及随时在生产环境中进行代码变更。


基于容器的微服务架构改变了开发和运维团队测试和部署现代应用程序 / 服务的方式。容器通过简化应用程序的扩缩容和部署来帮助公司实现现代化,但容器也创建了一个全新的基础设施生态系统,从而引入了新的挑战和更多的复杂性。


无论是大型软件公司还是小型软件公司,现在每天都要部署数千个容器实例,这种扩缩容的复杂性是他们必须要管理的。那么他们是怎么做的呢?



秘诀就是 Kubernetes


Kubernetes 最初由 Google 开发,是一个开源的容器编排平台,旨在自动化容器化应用程序的部署、扩缩容和管理。


在本教程中,我们将介绍如何将 Kubernetes 纳入到现有的传统 CI/CD 管道中,并实现服务的高可用性,以及随时(是的,任何时候都不会影响服务)在生产环境中进行代码变更。


使用到的工具


本文是基于你对如下主题有基本 / 良好的理解的基础上的。


  • Kubernetes(我们的服务在 Kubernetes 上运行)

  • Jenkins 以及 Jenkins 共享库(CI/CD 工具)

  • GIT(SCM 工具)

  • HAProxy(网络负载均衡器)

  • Ansible(配置管理工具)


CI/CD 安装


  • Jenkins 服务器——与 Docker、Ansible 和 Kubectl 一起安装(将 Kube 管理配置.kube 从 K8s master 复制到 Jenkins 服务器的主目录中)

  • 具有一主两从三个节点的 K8s 集群

  • HAProxy 服务器


使用 K8s 的 CI/CD


GIT & Jenkins


让我们来详细介绍一下如何配置所有这些不同的工具,并使其能够完美地运行。


我们的示例应用程序,名为 shoppingapp,在 GitHub 中有三个存储库,每个库都具有特定的微服务。


  • shoppingapp-home:首页微服务

  • shoppingapp-kids :儿童版页面微服务

  • shoppingapp-mens:男士版页面微服务


类似地,针对这三个库我们有三个 Jenkins 管道作业,并在存储库中设置了 GitHub webhook,以便在有新提交时自动启动构建。



Jenkins 管道作业


我们来看下 shoppingapp-home 作业的配置。




Jenkins 管道配置


在 shoppingapp-home 的管道作业中,仓库 URL 指向 shoppingapp-home 的 GitHub 存储库。类似地,另外两个管道作业也指向各自的存储库。


下面是 shoppingapp-home 存储库中的 Jenkinsfile。


@Library('jenkins-shared-library') _pipeline {   agent any   environment {       app = 'shoppingapp'       service = 'shoppingapp-home'       registryCredential = 'dockerhub'       dockerImage = ''       imageid = "deepanmurugan/shoppingapp-home:$BUILD_NUMBER"   }   stages {       stage('Build') {            steps {        script {            dockerImage = dockerbuild(imageid)        }        }         }       stage('Test') {           steps {                        testcase()           }       }       stage('Publish') {           steps{               script {            imagepush(imageid)                   }           }       }       stage('Pull Playbook Repo') {        steps {        dir('/tmp/ansible-playbooks/') {            gitcheckout(                branch: "master",                repoUrl: "https://github.com/deepanmurugan/Ansible_Playbook.git"            )        }    }       }       stage ('Deploy') {           steps {           dir('/tmp/ansible-playbooks/') {               script{            deploytok8s(imageid,app,service)               }           }           }       }   }}
复制代码


shoppingapp-home 存储库的 Jenkinsfile 以下是管道作业中的不同步骤。作业声明了几个变量,app——指我们的应用程序名,service——指我们的服务名,registryCredentials——是我们保存在 Jenkins 中的 dockerhub 用户名和密码,imageid——带有标签的 Docker 容器镜像名,这里的标签将是 Jenkins 的内部版本号。


在上面的 Jenkinsfile 中,我使用了共享库(如果你不熟悉共享库的话,请参考 Jenkins 网站)。


在“Build”(构建)阶段,我在共享库中调用了函数dockerbuild,并将 imageid 作为参数进行传递。以下是dockerbuild函数的定义。


def call(String dockerImage) {  script {    docker.build "${dockerImage}"  }}
复制代码


Build 阶段


它仅使用我们传递的 imageid 作为参数调用 docker.build,就会触发docker build -t imageid, 并基于 Dockerfile 创建一个 Docker 镜像。我们稍后再看 Dockerfile。


下一步是“Test”(测试),此时我们可以运行测试用例。我目前不执行任何测试用例,因为这是一个非常基础的应用程序。


def call() {    sh """        echo "Testing the docker built image"    """}
复制代码


Test 阶段


接下来,我们进入“Publish”(发布)阶段,该阶段将再次调用imagepush函数,其中 imageid 作为共享库中的参数。该函数基本上要登录到 Docker Hub,并将镜像推送到 Docker Hub 中。


def call(String dockerImage) {  echo "${dockerImage}"  withCredentials([usernamePassword(credentialsId: 'dockerhub', usernameVariable: 'hubUsername', passwordVariable: 'hubPassword')]) {        sh """            docker login --username="${hubUsername}" --password="${hubPassword}"            docker push "${dockerImage}"        """    }}
复制代码


Publish 阶段


下一步是“Pull Playbook Repo”,仅克隆存储库,该库中包含了我们所有的 playbook。


def call(Map stageParams){  checkout([$class: 'GitSCM', branches: [[name: stageParams.branch]], userRemoteConfigs: [[credentialsId: 'github_repo', url: stageParams.repoUrl]]])}
复制代码


Pull Playbook Repo 阶段


接下来是“Deploy”(部署)阶段,该阶段触发 playbook 将容器部署到 Kubernetes 集群中。


def call(String dockerImage, String app, String service) {    sh """        ansible-playbook deploy_k8s.yml --extra-vars \"image_id=${dockerImage} app_name=${app} service_name=${service}\"    """}
复制代码


Deploy 阶段


现在,我们对如何开发和维护每个微服务的存储库、如何配置 Jenkins 管道来创建 Docker 镜像并将镜像推送到 Docker Hub 以及触发 Ansible Playbook 将容器部署到 K8s 集群都已经相当清楚了。那我们来看一下它的 Dockerfile 是什么样的。


Dockerize 应用程序


FROM python:3.7.3-alpine3.9RUN mkdir -p /appWORKDIR /appCOPY ./src/requirements.txt /app/requirements.txtRUN pip install -r requirements.txtCOPY ./src/ /appENV FLASK_APP=server.pyCMD flask run -h 0.0.0.0 -p 5000
复制代码


Dockerfile


Dockerfile 使用 python:3.7.3-alpine3.9 作为基础镜像,我们安装了一个 flask 应用程序来打印某些文本。该应用程序运行在端口 5000 上。


使用 Ansible Playbook 来进一步接管


下面是 Ansible Playbook 的 deploy_k8s.yml,它是由 Jenkins 管道作业触发的。


- hosts: localhost  user: ubuntu  tasks:  - name: Deploy the service    k8s:      state: present      definition: "{{ lookup('template', 'k8s/{{app_name}}/{{service_name}}/deployment.yml') | from_yaml }}"      validate_certs: no      namespace: default  - name: Deploy the application    k8s:      state: present      validate_certs: no      namespace: default      definition: "{{ lookup('template', 'k8s/{{app_name}}/{{service_name}}/service.yml') | from_yaml }}"  - name: Deploy the Ingress    k8s:      state: present      validate_certs: no      namespace: default      definition: "{{ lookup('template', 'k8s/{{app_name}}/common/ingress.yml') | from_yaml }}"
复制代码


使用 Ansible 部署 K8s 组件


Kubernetes 集群


现在我们来看一下 K8s 集群。集群中有一个主节点和两个工作节点。


ubuntu@kube-master:~$ kubectl get nodesNAME STATUS ROLES AGE VERSIONkube-master Ready master 10d v1.19.4kube-worker1 Ready <none> 10d v1.19.4kube-worker2 Ready <none> 9d v1.19.4
复制代码


此外,我们还安装了 Traefik Ingress 控制器,作为集群中两个副本的部署(deployment)。


ubuntu@kube-master:~$ kubectl get pods -n kube-system|grep ingresstraefik-ingress-controller-6b7f594d46–5jqzq 1/1 Running 0 7d12htraefik-ingress-controller-6b7f594d46-vvfch 1/1 Running 0 8d
复制代码


为了无缝地部署 / 扩展我们的服务,我们以特定的格式组织了 Ansible Playbook 库。



K8s 服务定义的目录结构


每个服务都有两个特定于该服务的文件 deployment 和 service,common 目录中则包含了 ingress 配置定义。


apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: "{{ app_name }}"  name: {{ service_name }}-deloymentspec:  replicas: 2  selector:    matchLabels:      app: "{{ app_name }}"      task: "{{ service_name }}"  template:    metadata:      labels:        app: "{{ app_name }}"        task: "{{ service_name }}"    spec:      containers:      - name: {{ service_name }}-pod        image: "{{ image_id }}"        imagePullPolicy: Always        ports:        - containerPort: 5000      imagePullSecrets:        - name: dockerhubsecret  strategy:    type: RollingUpdate    rollingUpdate:      maxSurge: 1      maxUnavailable: 0
复制代码


deployment.yml


上面的 deployment 文件是通用的,它从 Jenkins 管道作业中获取所有传输到 deploy_k8s.yml 的变量,并将其传输到该 K8s 的 deployment.yml 中。因此,若要用更多的微服务来扩展应用程序,只需在 Ansible Playbook 库中创建适当的目录结构以及具有 ingress 配置的 Jenkins 管道,即可实现完美地运行。


在创建部署之后,我们需要创建一个服务来公开该部署。该服务将端口 80 映射到 pod 的端口 5000。


apiVersion: v1kind: Servicemetadata:  name: {{ service_name }}-servicespec:  selector:    app: "{{ app_name }}"    task: "{{ service_name }}"  ports:    - protocol: TCP      port: 80      targetPort: 5000      name: http
复制代码


service.yml


Deployment.yml 和 Service.yml 文件对于 shoppingapp 服务下的所有微服务都是通用的。


另外,我们看一下 common/ingress.yml 中 ingress 配置。ingress 的主机(host)名是 app.shoppingapp.com,它具有基于路径的规则,可将流量重定向到特定的服务。


apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: {{ app_name }}-ingress  annotations:    kubernetes.io/ingress.class: traefik    traefik.frontend.rule.type: PathPrefixStripspec:  rules:  - host: app.shoppingapp.com    http:      paths:      - path: /home        backend:          serviceName: shoppingapp-home-service          servicePort: http      - path: /kids        backend:          serviceName: shoppingapp-kids-service          servicePort: http      - path: /mens        backend:          serviceName: shoppingapp-mens-service          servicePort: http
复制代码


ingress.yml


引入 HAProxy


另外,我还使用了 HAProxy 负载均衡器来平衡 K8s 集群中两个节点之间的流量。我已经将前端和后端添加到现有的 HAProxy 配置文件中。后端服务器是 K8s 集群中的工作节点。


frontend http_frontbind *:80mode httpdefault_backend http_back
复制代码


backend http_backbalance roundrobinserver kube 172.31.35.122:32365 checkserver kube 172.31.40.13:32365 check
复制代码


端口 32365 是 traefik-ingress-service 服务公开的端口。DNS 是为 ingress.yml 中提到的主机名 app.shoppingapp.com 创建的,该主机名会被解析为 HAProxy IP(我使用的是 AWS Route 53 内部域名来创建的域名和 DNS 记录)


ubuntu@jenkins_ansible:~$ kubectl describe svc traefik-ingress-service -n kube-systemName: traefik-ingress-serviceNamespace: kube-systemLabels: <none>Annotations: <none>Selector: k8s-app=traefik-ingress-lbType: NodePortIP: 10.102.149.216Port: web 80/TCPTargetPort: 80/TCPNodePort: web 32365/TCPEndpoints: 10.244.1.99:80,10.244.3.19:80Port: admin 8080/TCPTargetPort: 8080/TCPNodePort: admin 31387/TCPEndpoints: 10.244.1.99:8080,10.244.3.19:8080Session Affinity: NoneExternal Traffic Policy: ClusterEvents: <none>
复制代码


真实的流程


对于这个为我们的微服务应用程序而创建的 CI/CD 管道,其所需的所有组件我们都已经了解了。现在,让我们将这些组件组装起来,以了解该流程的工作原理。


  • 开发人员提交代码到微服务仓库(shoppingapp-kids)

  • GitHub 中配置的 Webhook 通知 Jenkins 并触发相应的管道作业(shoppingapp kids)

  • 管道作业克隆 shoppingapp-kids 存储库,并开始执行 Jenkinsfile。

  • Jenkinsfile 中的构建阶段使用克隆的 shoppingapp-kids 存储库中的 Dockerfile 创建 Docker 镜像(deepanmurugan/shoppingapp-kids:21)。

  • 测试 Docker 镜像,如果测试通过,则将镜像推送到 Docker Hub。

  • 触发 Ansible Playbook,使用 app_name、service_name 以及 image_id 变量将 Docker 镜像部署到 K8s 集群。

  • Ansible Playbook 将读取所有与 deployment/servive/ingress 相关的 K8s 定义,并在集群中创建所需的组件。


向管道中添加新的微服务


假设我们有一个请求,要求在该架构中再添加一个名为 shoppingapp-ladies 的微服务。开发人员创建了一个名为 shoppingapp-ladies 的存储库,并使用相同的 Docker 和 Jenkinsfile 提交了代码,唯一的变化是 Jenkinsfile 中的 service_name=shoppingapp-ladies 变量。



修改文件夹结构后,添加新的微服务


修改 common/ingress.yml,并添加一个名为 /ladies 的新路径,端点是 shoppingapp-ladies-service。


- path: /ladiesbackend:serviceName: shoppingapp-ladies-serviceservicePort: http
复制代码


拷贝现有的 Jenkins 管道作业,并创建一个名为 shoppingapp-ladies 的新管道作业。



Jenkins 管道作业列表


在新作业 shoppingapp-ladies 的管道中,只需添加新的存储库 URL,然后执行管道作业,仅此而已。它将创建一个新的部署和服务并修改 ingress。


ubuntu@jenkins_ansible:/opt/python$ curl app.shoppingapp.com/ladiesWelcome to shoppingapp — Ladies section — shoppingapp-ladies-deloyment-656f6f9d9f-dms8w
复制代码


原文链接


https://medium.com/awsblogs/ci-cd-with-kubernetes-3c29e8073c38

2020-12-29 17:073819

评论 1 条评论

发布
用户头像
部署图画的很形象
2020-12-30 12:44
回复
没有更多了
发现更多内容

质押挖矿模式系统开发,矿池系统部署搭建

V\TG【ch3nguang】

挖矿矿池系统开发案例 质押挖矿

文心一言 VS 讯飞星火 VS chatgpt (81)-- 算法导论7.4 6题

福大大架构师每日一题

福大大架构师每日一题

mysql基础——认识索引

树上有只程序猿

MySQL 索引

BetterZip 5中文下载+BetterZip 5注册码

mac大玩家j

Mac软件 解压缩工具 压缩软件

推荐前 6 名 JavaScript 和 HTML5 游戏引擎

3D建模设计

游戏引擎

【中危】Spring Kafka 反序列化漏洞 (CVE-2023-34040)

墨菲安全

网络安全 漏洞情报

隐语纵向联邦 SecureBoost Benchmark白皮书

隐语SecretFlow

大数据 AI 数据安全 隐私计算 开源社区

交易所系统开发/秒合约交易所/锁仓挖矿/前端uinapp

V\TG【ch3nguang】

交易所开发 秒合约

Sentieon | 应用教程: TNscope®使用机器学习模型进行有匹配正常样本的体细胞变异发现

INSVAST

基因测序 应用教程 TNscope

基于 Argo CD 与 Argo Workflows 的 GreptimeDB 云端自动化升级实践

Greptime 格睿科技

rust 时序数据库 云原生数据库 国产时序数据库 自动升级

量化智能机器人开发,炒币机器人功能部署搭建

V\TG【ch3nguang】

量化交易机器人开发 炒币机器人

HoudahSpot最新中文版+补丁安装教程

胖墩儿不胖y

Mac软件 文件搜索 搜索工具 搜索软件

动态规划-编辑距离-两字符串集合重排序

alexgaoyh

重排序 动态规划 编辑距离 文本对齐 编辑距离变化过程

Paper推荐|「隐私集合求交PSI系列」奖励升级

隐语SecretFlow

大数据 数据安全 隐私计算 开源社区 论文推荐

Microsoft Office LTSC 2021 for Mac v16.77 beta中文版

mac

办公软件 苹果mac Windows软件 office2021

一文讲透低代码开发的优势

高端章鱼哥

软件开发 低代码 应用开发 JNPF

开源微服务如何选型?Spring Cloud、Dubbo、gRPC、Istio 详细对比

阿里巴巴云原生

阿里云 云原生 dubbo

ARTS 打卡第二周

直须

个人成长 前端 ARTS 打卡计划

高效数据传输与管理利器:镭速传输方案助力企业提升效率与安全

镭速

数据传输 分发数据 管理数据 镭速数据传输

如何在浏览器中启用 WebGL 以使用 HTML5 3D 查看器

3D建模设计

html5 WebGL 3D 查看器

WiFi7 is coming -IPQ9574-QCN9274-speeds up to 30Gbits per second-quaclomm-chipset

wifi6-yiyi

WiFi7 30g

ARTS 打卡第二周

直须

个人成长 前端 ARTS 打卡计划

Node.js 的 Buffer 是什么?面向开发者的指南

Liam

JavaScript node.js 程序员 后端 buffer

Tableau Desktop 2019 for Mac(全能数据分析工具) v2019.1.0激活版

mac

数据分析工具 Tableau Desktop 2019 苹果mac Windows软件

五种重要的 AI 编程语言

3D建模设计

人工智能 AI

浪潮信息 KeyarchOS 助力 IT 企业安全管理业务完成 CentOS 迁移替换 | 龙蜥案例

OpenAnolis小助手

开源 操作系统 IT 浪潮信息 龙蜥案例

6种限流实现,附代码![通俗易懂]

王磊

Java Java面试题

【高危】Kubernetes Windows节点kubernetes-csi-proxy提权漏洞 (CVE-2023-3893)

墨菲安全

网络安全 漏洞情报

PyTorch 提高生产力的技巧

3D建模设计

机器学习 PyTorch

7个用于机器学习和数据科学的基本 Python 库

3D建模设计

Python AI人工智能

StarRocks 存算分离技术探索活动回顾

StarRocks

数据库 数据仓库 OLAP 存算分离

每天部署数千个容器实例,扩缩容复杂性该如何管理?_服务革新_Deep_InfoQ精选文章