Introduction
Currently, a majority of our users leverage the Harness UI to onboard applications. However, this requires the Harness Owner or user to manually click through the UI and configure applications for onboarding teams. Sometimes, there are centralized teams that are tasked with managing Harness and have to do the setup themselves. Luckily, there is a fair alternative that empowers onboarding development teams to automate the creation of their applications and leverage some base configuration to get started. This includes the basic setup of Harness account level entities like Cloud Provider and Artifact Sources. At the Application level, the ‘Managing Harness Config in Git’ technique allows easy revert of changes to a workflow, pipeline, service, or an environment. It’s all tracked in Git, Audited in Harness and allows more granular control of what changes are being made within Harness. Developers enjoy living in their code, if it’s one less screen to navigate to, chances are they would gladly take it. From an Onboarding perspective, one bottleneck we see is the dependency of a centralized team to onboard all the various teams. Chances are that these centralized teams are small and are not full-time Harness Administrators. They tend to do this in conjunction with their current job and it can become overwhelming.
Use Cases
- A common use case we see is that developers don’t want to navigate to another screen to configure their deployment workflows and pipelines like Jenkins.
- Sometimes UI’s take to long to navigate, with the Harness YAML Config folder structure its easier for a developer to navigate through to their specific application.
- A User wants to segment their application from the overall Harness Configuration and just manage all the manifests and Harness configs in 1 repository.
- Create a Golden Application and leverage that application to onboard other applications.
The Playbook
Below is the playbook which allows you as a Harness admin automate and easily onboard other teams without having to do much manually work in the UI. We will start by creating a Golden Application and some reusable Account Configuration.
Pre-Requisite
- Please Enable Harness Account Level Git Sync
Building the Golden Template Application
1. The Cloud Provider Setup
To start, we will need a Sample Cloud Provider to work off of. This will be a UI Driven because we want to make sure all the base configuration is set up for the application is ready to go.
In this case, we are providing a few pieces of information for the “Golden Application’s Cloud Provider”:
Name: GoldenCanaryCloud
MasterURL: "https://36.144.554.9452
ServiceAccountToken: "changeMe"
SkipValidation: √
The MasterURL, in this case, is related to the Kubernetes Cluster you are leveraging. If the delegate is using a service account, for now, you can pass in a dummy service account token. When selecting the Skip Validation option, Harness won’t validate that the Cloud Provider Information is correct. This is useful because rather than inputting real credentials into the Cloud Provider, the YAML correlated to this cloud provider can be manipulated and changed to match real credentials later on. When changing the service account token to a legitimate one, please paste it in the UI because it will be encrypted by our Harness KMS.
2. The Application
Create an application called “GoldenCanary”. This will serve as the Golden Application that other teams can leverage through Configuration As Code! Be sure to enable Git Sync so the YAML files that are part of “GoldenCanary” can be copied and manipulated for other applications.
3. The Service
Create the Golden Sample Kubernetes Service. This Service can be manipulated and copied for other Application teams.
Once the Service is submitted, most of the time teams leverage a remote repository to manage their manifests that aren’t associated with Harness. This is because they want to keep the Kubernetes Deployment YAML outside of Harness Configuration and manage it on their own. So Please Select “Link Remote Repository” and pick one from the Source Repository you have leveraged for this Golden Application. This Repository has the base sets of configuration to leverage in Harness.
Some Sample Files for you to leverage as a remote repository:
deployment.yaml:
{{-
if
.Values.env.config}}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{.Values.name}}
data:
{{.Values.env.config | toYaml | indent
2
}}
---
{{- end}}
{{-
if
.Values.env.secrets}}
apiVersion: v1
kind: Secret
metadata:
name: {{.Values.name}}
stringData:
{{.Values.env.secrets | toYaml | indent
2
}}
---
{{- end}}
{{-
if
.Values.dockercfg}}
apiVersion: v1
kind: Secret
metadata:
name: {{.Values.name}}-dockercfg
annotations:
harness.io/skip-versioning:
true
data:
.dockercfg: {{.Values.dockercfg}}
type: kubernetes.io/dockercfg
---
{{- end}}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{.Values.name}}-deployment
spec:
replicas: {{
int
.Values.replicas}}
selector:
matchLabels:
app: {{.Values.name}}
template:
metadata:
labels:
app: {{.Values.name}}
spec:
{{-
if
.Values.dockercfg}}
imagePullSecrets:
- name: {{.Values.name}}-dockercfg
{{- end}}
containers:
- name: {{.Values.name}}
image: {{.Values.image}}
{{-
if
or .Values.env.config .Values.env.secrets}}
envFrom:
{{-
if
.Values.env.config}}
- configMapRef:
name: {{.Values.name}}
{{- end}}
{{-
if
.Values.env.secrets}}
- secretRef:
name: {{.Values.name}}
{{- end}}
{{- end}}
namespace.yaml
{{-
if
.Values.createNamespace}}
apiVersion: v1
kind: Namespace
metadata:
name: {{.Values.namespace}}
{{- end}}
service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{.Values.name}}-svc
spec:
type: {{.Values.serviceType}}
ports:
- port: {{.Values.servicePort}}
targetPort: {{.Values.serviceTargetPort}}
protocol: TCP
selector:
app: {{.Values.name}}
values.yaml
name: harness-example
replicas:
1
image: ${artifact.metadata.image}
dockercfg: ${artifact.source.dockerconfig}
createNamespace:
true
namespace: ${infra.kubernetes.namespace}
# Service Type allow you to specify what kind of service you want.
# Possible values
for
ServiceType are:
# ClusterIP | NodePort | LoadBalancer | ExternalName
serviceType: LoadBalancer
# A Service can map an incoming port to any targetPort.
# targetPort is where application is listening on inside the container.
servicePort:
80
serviceTargetPort:
80
# Specify all environment variables to be added to the container.
# The following two maps, config and secrets, are put into a ConfigMap
# and a Secret, respectively.
# Both are added to the container environment in podSpec as envFrom source.
env:
config:
key1: value1
secrets:
key2: value2
4. The Environment
Now its time to configure the Environment. We will configure one environment for Prod and one for Dev. The environment for Prod should be configured something like this:
The Namespace Variable is being populated at the Environment level. As you can see, the value Prod is being assigned to Namespace.
The Corresponding Infra Definition should look something like this:
As seen in the image, the namespace is coming from the environment!
Now let’s create a Dev Environment, it will be similar to the Prod Environments setup.
It also has a similar Infrastructure Definition Setup
5. The Workflow
We are going to create a templated Rolling Deployment that other teams can leverage through Configuration as Code. This technique is helpful because it allows for a standardization of deployment. Teams can create a templated workflow that can be managed and controlled by engineering leads or DevOps engineers. Development teams can deploy the same way and don’t have to worry about going into the UI. They just change a few fields of YAML to deploy their service.
After creating the GoldenRollingWorkflow, we can templatize these fields by clicking on the ‘T’ field. This will allow any service with the corresponding environment and Infrastructure Definition to leverage the workflow.
6. The Pipeline
We will be creating a Three-Stage Pipeline for Teams to use. This Pipeline will do a rolling deployment into the Dev environment, Have an Approval Step, and then execute a rolling deployment into the Production environment. This is a basic use case and can be iterated upon to be far more complicated.
The First Stage should be created similar to this:
You should populate the dropdowns with “Dev” Environment and “Dev” Infrastructure Definition. Select SampleK8s as the Service.
The Second Stage is an approval step and should be created like so:
The Third Stage is the deployment to Production Stage. This results in:
The Overall Pipeline should look something like this:
Creating the New Application in GitHub
In the Setup section, we created a Git Sync to a designated Harness GitHub repository. Please make sure that the Webhook from Harness to GitHub is configured!
Here is where you can retrieve your webhook: Git Connector → → Generate Webhook URL
Pass this Webhook into GitHub Repositories WebHook Section. Ensure that the payload is of type “application/json”
Once Configured, your Repository should look something like this:
Navigate to the Applications folder and view the GoldenCanary Application.
As you can see, your application is comprised of YAML files. These Yaml files define all the various Harness entities that are associated with the Application.
Since BiDirectional Sync is Setup, Harness can push into GitHub and GitHub can push to Harness. Let’s create another Application called Duck. This time we will be doing it as Code. Open an editor and start tweaking a copy of the GoldenCanary Application!
- Copy the Application
- Rename the Application
- Change the Description of the Application
- Rename the Service
- Edit the Service Fields in the Pipeline. Since the workflows are templatized, no need to edit the Workflows fields.
The Finished Pipeline should look something like this:
harnessApiVersion:
'1.0'
type: PIPELINE
pipelineStages:
- type: ENV_STATE
name: Rolling Deployment to Dev
parallel:
false
skipCondition:
type: DO_NOT_SKIP
stageName: Dev Rolling Deployment
workflowName: GoldenRollingDeployment
workflowVariables:
- entityType: INFRASTRUCTURE_DEFINITION
name: InfraDefinition_Kubernetes
value: Dev
- entityType: ENVIRONMENT
name: Environment
value: Dev
- entityType: SERVICE
name: Service
value: Flocks
- type: APPROVAL
name: Approval
1
parallel:
false
properties:
userGroups:
- OwqgwBkJSt2Vqlv-_TNfUA
pipelineStageElementId: uohkYo2JRCm519Rv9W-1lg
stageName: Approval to Prod
disable:
false
timeoutMillis:
604800000
disableAssertion:
null
pipelineStageParallelIndex:
2
approvalStateType: USER_GROUP
pipelineId: Jy3GTC44RkSexTtYrejU2Q
skipCondition:
type: DO_NOT_SKIP
stageName: Approval to Prod
- type: ENV_STATE
name: Prod Deployment
parallel:
false
skipCondition:
type: DO_NOT_SKIP
stageName: Prod Rolling Deployment
workflowName: GoldenRollingDeployment
workflowVariables:
- entityType: INFRASTRUCTURE_DEFINITION
name: InfraDefinition_Kubernetes
value: Production
- entityType: ENVIRONMENT
name: Environment
value: Prod
- entityType: SERVICE
name: Service
value: Flocks
- Save and commit the changes!
You should see the following entities in your Account!
The Application:
The Internals of the Application: Service, Pipeline, Workflows
And that’s it! That’s how you can create applications through configuration as code.
Power Users of Managing Harness Config in Git
Power users can incorporate automation scripts to manipulate the fields of the YAML. Some sample scripts we have seen in the field are based on an input in a UI or Shell Script, Harness YAML files are generated and stored in a Git Repository. The YAML is then synced to Harness through the Git Sync process which can also be automated through scripts. Users can leverage tools like YQ to manipulate specific YAML fields inline.
A Sample Flow for the automation of YAML Generation
- Create a Golden Application that is fully templatized
- Create a Script that copies the Cloud Provider YAML and manipulates designated fields
- Create a Script that creates a new application, copies the content of the golden application into it, and edits the necessary fields to create a minimal viable application
- Script to edit the cloud provider YAML to scope to the new application
- Commit the changes to GitHub and review the results in the UI
If there are issues, Harness will through Git Sync errors for the user to react and change. If all goes well, your new application will be generated with a few inputs.
Conclusion
Managing Harness Config in Git has brought the deployment closer to the developers and has enabled them to live in their code. As a developer, they don’t have to check the status of their deployment in the UI anymore, its a simple notification or an API call through GraphQL. These Harness components that live in code are reusable and are versioned so that if anything breaks or is altered, there is a working version to revert back to. To live in code is a developers haven and they do not want other tools to bog down their development flow. Hopefully, this article provides you a guide on how to go from No Harness Configuration management to a safe, version controlled, and easy way to manage Harness entities.
Bonus Architecture
Using the GraphQL APIs now available, our users can now do a combination of Git Sync and API to automate onboarding. Check out this link: Harness GraphQL API for Onboarding Automation
The other piece to this is having a plan on how the flow should go, here is one that I usually recommend:
- Create an Application
a. Set up Application Git Sync - Create the User Group
a. Set User Group Permissions
b. Set the User Group SSO Setting (this will sync to LDAP and get the users) - Create Application Secrets via API
a. Set the scope for the secrets - Cloud Provider Configuration
a. Set Scope to the Application - Copy Files for Template App into the created application