paint-brush
是如何动用 Octopus 和 TeamCity 细化 CI/CD 由@socialdiscoverygroup
4,171 讀數
4,171 讀數

如何使用 Octopus 和 TeamCity 简化 CI/CD

根据 Social Discovery Group13m2024/05/14
Read on Terminal Reader

太長; 讀書

众所周知,如果没有清晰、有组织的流程,开发人员可能难以有效协作,从而导致软件更新延迟。在本文中,Social Discovery Group 团队分享了如何使用 TeamCity 和 Octopus 构建便捷、灵活的 CI/CD 管道。
featured image - 如何使用 Octopus 和 TeamCity 简化 CI/CD
Social Discovery Group HackerNoon profile picture
0-item


众所周知,如果没有清晰、有条理的流程,开发人员可能难以有效协作,从而导致软件更新延迟。几年前,Social Discovery Group 团队面临着 CI/CD 流程不理想的挑战。当时,团队使用了 TeamCity 和 Octopus,它们各有优势。例如,Octopus 便于部署,而 TeamCity 适合自动化测试,并且对于项目构建来说也足够方便。为了构建一个全面、视觉上吸引人的 CI/CD 管道,并在配置上尽可能方便灵活,必须使用多种工具。多个项目的代码存储在 Bitbucket 上的本地存储库中。SDG 团队研究了这个问题,并决定使用现有工具优化流程。


主要优化目标:

  1. 从 TeamCity 自动构建和部署到指定环境。
  2. 命名构建:在主分支中添加“release”,以通过名称区分构建。
  3. 在推送到各个服务的各个测试环境上的相应分支时自动构建和部署。
  4. 建立一个流程,在部署到暂存区和生产区之前,必须先完成部署到测试和开发环境。这已在 Octopus 中实现。


SDG 团队协作判断用到 TeamCity 实施实现和智能化测试方法,用到 Octopus 实施推进。


TeamCity 中实现了什么:

  1. TeamCity 的免费吧的版本可以运行三大一级加盟,这我们对 SDG 团队图片并不是以及充裕了。孩子们装置好几个个新一级加盟,将其添加图片到池中,并将其运用于孩子们的模版。
  2. 在实用最薪旧版的 TeamCity 时,公司合作正处于 Ubuntu Server 上事情。信息显示屏微信截图信息显示了公司合作实用的增加软件:



  1. 在工具中,团队添加了插件,例如用于报告创建的 Allure 2.14.0 和 Nuget 5.5.1。
  2. 为了简化类似任务的执行,SDG 团队为不同类型的部署创建了几个模板:NuGet 和服务。
  3. 每个模板都包含几个步骤,如下面的屏幕截图所示。


NuGet 的部署如下所示:




值得购买主要的是,跟据支系能不能为主导支系,在推送的版本中加入“-release”(流程 3、4)。


服务部署如下:


对于那些每一项安全服务保障,跟据整体局部数据(安全服务保障名字大全、%build.number% 等)替代相应的的局部数据。


屏幕截图中显示了 Docker Build 步骤的一个示例:


每个投资项目存储空间库都带有某些的 Dockerfile。


如前所述,步骤 4 和步骤 5 之间的区别如下:



%deploymentTarget%变量用作环境参数,在部署期间将 Octopus 中的相应阶段(例如,测试、开发)传递给该参数。当将更改推送到开发团队的各个分支(已配置)时,会自动执行构建并将软件部署到相应的测试环境。设置如下图所示。要连接 Octopus,需要添加两个全局参数:octopus.apiKey 和 octopus.url



再者,SDG 技术团队在“连结”部位为几乎所有内容连结好几回个通用的的 NuGet 随意调节库和容器等公司注册表。


还有,SDG 提倡在光学到信件知会程序代码要素配资光学到信件知会,在备份数据数据要素制定成备份数据数据,打造必备的组,分发应当的作用,并将用户名增多到所需要的组。常见制定成已结束,接下来,精英团队提倡期限观察不断不断更新并一个季度不断不断更新多次 TeamCity。


收起来,Social Discovery Group 项目团体開始手机调试 Octopus。文章没说明装设小细节、差不多微信用户访问权限制定和一些各方面,所以您行枯燥地自己来完成这种运营。项目团体直接避免了健康周期性方面,该方面在 Library 部份中进行手机调试。在下面的显示屏高清截图中,您行知道 SDG 项目团体的范本具体步骤:



之后,技术团队在全局数据类型一起按题材建设其它一定的全局数据类型组。为每位全局数据类型设定值,并保持对生活环境、工作对象和工作对象脚色(标签设计)的依赖感的关联。下部的霸屏屏幕截图信息显示新一个例子:



Kubernetes 中的群集式是的受众,的受众角色名是浮动到有效群集式或测算机场景的标识。大多数这种都行以在基本条件油烟净化器部份中进行配制。


还可能对楼盘来分组进行,并可能制定更方便的仪表盘板来提示 部署工作在其上的工作、时候和安卓版本。 SDG 的的部署工作下面:所以各种测试一时段.合作为一款 方法,作为鸟卵新创建一款 代用微信小程序模板,一时段.和城市热力图一时段.也是非常。


下面的截图展示了 SDG 团队的情况:

在右侧,选择了之前描述的生命周期。部署包阶段包含相当简单的默认设置。

在 Deploy Raw Kubernetes Yaml 阶段中,SDG 人员选用了万能的自写 Yaml 建筑模板。接着以 Kubernetes Script 为例子做更详尽的讲解。还编辑了用蓝色标示的相对基本参数。直得需要注意的是,在 Variables->Variable Sets 下拉菜单栏中相连接了一定的全部变数组,在 Variables->Project 下拉菜单栏中快速设置了项目流程特定的的变数,二者具极高的优先权级。


在下面中,SDG 管理团队绝对跳出譬如为业务插入标志、设置成勾起器或某个每项详情这种东西的详情。使自己喜爱2个至关重要的导航栏项:1 - 上线,您需要总是在在这当中产看相关的上线的板本和新建时间;此内容也展示在业务仪容仪表板上,2 - 因变量值->图片预览,您需要在在这当中产看哪种因变量值将删除相关的过程。





现在来是最沉要的个方面——在 Kubernetes 集群式核心区署 Yaml 摸板。患者是在 Library->Step Templates 个方面創建的。后面,SDG 团体体现了施用其指标值的电脑屏长截图。这对于一款指标值,您能能取舍一款性子、结构类型和默认要求值,各种增长描叙,它是强列推荐英文的。




本例中的代码如下:


 apiVersion: apps/v1 kind: Deployment metadata: name: '#{Octopus.Project.Name | ToLower}' namespace: #{Octopus.Environment.Name | ToLower} labels: Octopus.Kubernetes.DeploymentName: '#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}' spec: replicas: #{Replicas} strategy: type: RollingUpdate rollingUpdate: maxSurge: 25% maxUnavailable: 25% revisionHistoryLimit: 10 progressDeadlineSeconds: 600 selector: matchLabels: Octopus.Kubernetes.DeploymentName: '#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}' template: metadata: labels: Octopus.Kubernetes.DeploymentName: '#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}' spec: volumes: #{if usesidecar} - name: dump-storage persistentVolumeClaim: claimName: dumps-#{Octopus.Environment.Name | ToLower} #{/if} #{if MountFolders} #{each folder in MountFolders} - name: volume-#{folder | ToBase64 | Replace "\W" X | ToLower} hostPath: path: #{folder} type: DirectoryOrCreate #{/each} #{/if} - name: logs-volume hostPath: path: #{LogsDir} type: DirectoryOrCreate - name: appsettings secret: secretName: #{Octopus.Project.Name | ToLower} #{if Secrets} #{each secret in Secrets} - name: #{secret.name} secret: secretName: #{secret.name} #{/each} #{/if} #{if usesidecar} - name: diagnostics emptyDir: {} - name: dumps configMap: name: dumps defaultMode: 511 #{/if} containers: - name: #{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}-container image: #{DockerRegistry}/projectname.#{Octopus.Project.Name | ToLower}:#{Octopus.Release.Notes} #{if resources} resources: #{each resource in resources} #{resource.Key}: #{each entry in resource.Value} #{entry.Key}: #{entry.Value} #{/each} #{/each} #{/if} ports: - name: http containerPort: 80 protocol: TCP env: - value: "Development" name: "ASPNETCORE_ENVIRONMENT" - name: DD_ENV value: "#{Octopus.Environment.Name | ToLower}" - name: DD_SERVICE value: "#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}" - name: DD_VERSION value: "1.0.0" - name: DD_AGENT_HOST value: "#{DatadogAgentHost}" - name: DD_TRACE_ROUTE_TEMPLATE_RESOURCE_NAMES_ENABLED value: "true" - name: DD_RUNTIME_METRICS_ENABLED value: "true" volumeMounts: #{if usesidecar} - name: dump-storage mountPath: /tmp/dumps #{/if} #{if MountFolders} #{each folder in MountFolders} - mountPath: #{folder} name: volume-#{folder | ToBase64 | Replace "\W" X | ToLower} #{/each} #{/if} - mountPath: #{LogsDir} name: logs-volume #{if usesidecar} - name: diagnostics mountPath: /tmp #{/if} - name: appsettings readOnly: true mountPath: /app/appsettings.json subPath: appsettings.json #{if Secrets} #{each secret in Secrets} - name: #{secret.name} readOnly: true mountPath: #{secret.mountPath} subPath: #{secret.subPath} #{/each} #{/if} readinessProbe: httpGet: path: hc port: http scheme: HTTP initialDelaySeconds: #{InitialDelaySeconds} imagePullPolicy: IfNotPresent securityContext: {} #{if usesidecar} - name: sidecar image: '#{DockerRegistry}/monitor:3' command: - /bin/sh args: - '-c' - while true; do . /app/init.sh; sleep 1m;done env: - name: USE_MEMORY value: '2048' - name: PROJECT value: "#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}" resources: {} volumeMounts: - name: diagnostics mountPath: /tmp - name: dump-storage mountPath: /tmp/dumps - name: dumps mountPath: /app/init.sh subPath: init.sh shareProcessNamespace: true #{/if} affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: environment operator: In values: - "#{Node}" --- apiVersion: v1 kind: Service metadata: name: #{Octopus.Project.Name | ToLower} namespace: #{Octopus.Environment.Name | ToLower} labels: Octopus.Kubernetes.DeploymentName: '#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}' spec: type: ClusterIP selector: Octopus.Kubernetes.DeploymentName: '#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}' ports: - name: http port: 80 targetPort: http protocol: TCP --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: ingress.kubernetes.io/ssl-redirect: 'false' nginx.ingress.kubernetes.io/ssl-redirect: 'false' cert-manager.io/cluster-issuer: "letsencrypt-cluster-issuer" cert-manager.io/renew-before: '#{LetsencryptRenewBefore}' kubernetes.io/ingress.class: nginx #{if IngressAnnotations} #{each annotation in IngressAnnotations} #{annotation.Key}: #{annotation.Value} #{/each} #{/if} name: #{Octopus.Project.Name | ToLower} namespace: #{Octopus.Environment.Name | ToLower} labels: Octopus.Kubernetes.DeploymentName: '#{Octopus.Project.Name | ToLower}-#{Octopus.Environment.Name | ToLower}' spec: tls: #{if ExternalHost} #{each host in ExternalHost} - hosts: - #{host} secretName: #{Octopus.Project.Name | ToLower}-#{host | ToBase64 | Replace "\W" X | ToLower}-tls #{/each} #{/if} rules: #{if ExternalHost} #{each host in ExternalHost} - host: '#{host}' http: paths: - path: / pathType: ImplementationSpecific backend: service: name: #{Octopus.Project.Name | ToLower} port: name: http #{/each} #{/if} #{if usesidecar} --- apiVersion: v1 kind: ConfigMap metadata: name: dumps namespace: #{Octopus.Environment.Name | ToLower} data: init.sh: |- #!/usr/bin/env bash mem=$(ps aux | awk '{print $6}' | sort -rn | head -1) mb=$(($mem/1024)) archiveDumpPath="/tmp/dumps/$PROJECT-$(date +"%Y%m%d%H%M%S").zip" fullPathGc="/tmp/$PROJECT-$(date +"%Y%m%d%H%M%S").dump" echo "mem:" $mb" project:" $PROJECT "use:" $USE_MEMORY if [ "$mb" -gt "$USE_MEMORY" ]; then export USE_MEMORY=$(($USE_MEMORY*2)) pid=$(dotnet-dump ps | awk '{print $1}') dotnet-dump collect -p $pid -o $fullPathGc zip $fullPathGc.zip $fullPathGc mv $fullPathGc.zip $archiveDumpPath rm $fullPathGc fi #{/if}


Octopus 中的所有变量在代码中均以以下格式指定: '#{Octopus.Project.Name | ToLower}' ,其中最后一部分表示转换为小写。


最终一家配资zip文件是要为在 .NET 售后服务保障提升必须内存条空间利用减少时会自动保存图片其环境而打造的。这较大地作用了在开发设计工作中掌握内存条空间泄露并有效修复能力售后服务保障。


最后,服务仪表板如下所示:


的开发和测式销售团队看见利用此电子仪表板尤其便宜。


改善最终:


  1. SDG 团队构建了高效的 CI/CD 流程,大大提升了开发的速度和便捷性,团队在这个流程框架下工作了相当长一段时间。
  2. SDG 还将自动化测试引入了便捷的 TeamCity 工具和自动化服务部署。
  3. 通过用户友好的 Octopus 仪表板,团队配置了访问权限并可以管理部署和环境。
最后,SDG 在 Octopus 中保证了成千上万其他的性能。举例子,计划表在晚上自然开启云计算平台。


殊不知,需求美好是不止境的。Social Discovery Group 人员在理解 Azure DevOps 来深入推进大家 的的开发。大家 在 Helm 上的另一个生太系统软件中国铁建立了 Azure DevOps 步奏,愈发全面的和高质量。这将在下写一篇短文中间绍。


企业很诚心诚意听取意见您食用 Octopus 和 TeamCity 设计和优化调整 CI/CD 的临床经验。分享和交流您的看法和窍门!
바카라사이트 바카라사이트 온라인바카라