Jenkins: Managing Multiple Environment Configuration and Deployments

6/27/2019

I am working on a product where we have 3 dev teams.
1 for UI and
2 for backend.

Each team requires a complete env for their own testing. There 10+ backend services and many more other components and 4 UI components. We have following env:
3 Dev env one for each teams
1 Dev Integration
2 for QA (Automation and manual teasting)

All env are using Kubernetes, all services deployed as containers. Each env having their own DB server.
3 dev env and 1 dev int environment are deployed on single K8s Cluster and
2 QA env deployed on another cluster.

Each env has its own set of jenkins jobs for all modules (Both CI and CD). So we have total 6 copies of all jobs in various jenkins folders (1 for each env). They all use common svc and dpl file (Stored as template) from our devops repo to deploy services on their corresponding kubernetes env. and CD Jobs have all the necessary variables and values used with template files for corresponding env).

Now when any module has deployment related changes, we have to make common changes in dpl and svc files but any new config variables or change in existing config parameters need to be done in each env jobs. With Multiple version of product support, I foresee maintenance of more copies of complete set of jenkins jobs per version.

I have couple of ideas to reduce duplicate work but wanted to know What are my best options to reduce replication of changes and maintenance of so many sets of jobs. Please assist and let me know if more details are required.

Thanks! Ratish

-- Ratish Ratusaria
deployment
devops
jenkins
kubernetes

1 Answer

6/27/2019

This is way too long. TL;DR: Use helm and flux.

Long version:

I think this is putting too much of your CI/CD pipeline into Jenkins. It can work fine that way, but it's a lot cleaner when you assign CI responsibility to Jenkins and use a dedicated CD service. I recommend using Helm for deployments and using Weave Flux to manage them.

Helm is a package manager for Kuberentes. Essentially, it's just a way to parameterize your Kubernetes templates and install them with some default values and some overrides. Using helm alone would probably help you a lot.

Flux is a way of deploying your helm charts and docker images. It's essentially the CD in CI/CD. This diagram from the Flux website shows how Flux monitors your image repo for new artifacts created by Jenkins, and a config repo (your helm charts) for updated deployment configuration.

CI/CD Pipeline

So now, you've got Jenkins building your app, Helm able to deploy your Kubernetes configuration, and Flux able to watch for changes, how do you do multiple environments with some common and some custom configuration values? You can put values in 3 (or more places). 1) Your values.yaml which defines all the values your Helm chart uses, 2) env-shared-values.yaml this would have values shared across multiple environments, 3) service-env-values.yaml which is the specific values needed for an instance of a service.

An folder structure might look like this

  • HelmChartRepo
    • Chart
      • values.yaml
      • templates
        • all of your k8s templates here
    • EnvValues
      • dev-values.yaml
      • qa-values.yaml
    • Releases
      • dev1-svc1.yaml
      • dev1.svc2.yaml
      • dev2-svc1.yaml
      • dev2-svc2.yaml
      • qa1-svc1.yaml
      • etc

The glue is in the Release folder there. Each file is a HelmRelease which is what flux uses to manage a release. Here is an example I've used. Note a few things. 1) It's looking at a github repo for chart changes. 2) It's looking at a docker repo for images with a tag containing a specific prefix. This is how you can control different environments. Just have Jenkins tag the build appropriately and flux will deploy the new version.

---
apiVersion: flux.weave.works/v1beta1
kind: HelmRelease
metadata:
  name: dev1-svc1
  namespace: dev1
  annotations:
    flux.weave.works/automated: "true"
    flux.weave.works/tag.chart-image: glob:dev1-*
spec:
  releaseName: dev1-svc1
  chart:
    git: git@github.com:[your-user]/[your-chart-repo]
    path: [path in git to your chart]
    ref: master
  values: (release specific values here)

    image:
      repository: [mydockerhubrepo/myimagename]
      tag: dev1-versiontags
  valuesFrom:
  - chartFileRef:
      path: EnvValues/dev-values.yaml
      optional: false
-- frankd
Source: StackOverflow