Install Self-Managed Platform in Amazon Elastic Kubernetes Service (EKS)
This guide provides step-by-step instructions for deploying the Harness Self-Managed Platform (SMP) on Amazon EKS using Helm charts.
It outlines the necessary prerequisites, configuration steps, and recommended best practices to ensure a secure and efficient deployment on EKS.
Prerequisites
- AWS account with necessary IAM permissions to:
- Create EKS clusters and node groups.
- Create and attach IAM roles and policies.
- Provision VPC, subnets, and security groups.
- Create and manage IAM OIDC providers and service accounts.
kubectlAWS CLIeksctl- Helm Installed.
You can create an EKS cluster using either the AWS Management Console or the AWS CLI. However, this section focuses on using the AWS CLI and eksctl.
Ensure that both tools are installed and correctly configured before proceeding.
Step 1: Configure Your AWS Account
-
Open your terminal and run the following command. It will prompt you to enter your AWS credentials:
aws configure -
Provide your AWS credentials when prompted:
-
Access Key ID and Secret Access Key: You can access these from the AWS IAM Console.
-
Default region name: Specify the AWS region where you want to deploy the cluster (e.g., us-east-1).
-
Default output format: It's recommended to use
json.
Example:
AWS Access Key ID [None]: YOUR_ACCESS_KEYAWS Secret Access Key [None]: YOUR_SECRET_KEYDefault region name [None]: YOUR_REGIONDefault output format [None]: jsonNoteUse Step 3 to verify that your AWS account is configured correctly.
If the configuration appears saved but the verification fails, it's possible that the credentials are incorrect, expired, or lack necessary permissions.
Alternatively, you can export the credentials as environment variables, as shown below.
export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEYexport AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEYexport AWS_DEFAULT_REGION=YOUR_REGION -
-
To verify your configuration, run the following command:
aws sts get-caller-identityIf configured correctly, this command will return your AWS account information as shown below:
{"UserId": "AROASIYUWQHU2SSQKRFIB:<USER>@email-domain.xyz","Account": "<ACCOUNT-ID>","Arn": "arn:aws:sts::156272853481:assumed-role/AWSReservedSSO_AWSPowerUserAccess_687b2d551b4cfd18/<USER>@email-domain.xyz"}For additional help, refer to the official AWS CLI configuration documentation.
Step 2: Provision a Cluster
Before creating the cluster, ensure that a VPC and Elastic IPs are available for provisioning the SMP cluster.
-
Create a new YAML file (e.g.,
create-smp-cluster.yaml) using the sample configuration provided below.-
This configuration will provision an EKS cluster for your SMP environment.
-
The configuration sets up the following:
- A cluster named
<CLUSTER-NAME>in the<YOUR-AWS-REGION>region - Managed node groups
- Required IAM policies
- Networking settings necessary for running the Harness Self-Managed Platform
- A cluster named
-
The configuration comes with default values suitable for sandbox or testing environments. You can customize the values such as cluster name, region, tags, and CIDR ranges as needed.
accessConfig:authenticationMode: API_AND_CONFIG_MAPapiVersion: eksctl.io/v1alpha5# Modify these to your target region; update again if eksctl reports an unavailable Availability Zone for EKS nodes.availabilityZones: #- <YOUR-AWS-REGION-1>- <YOUR-AWS-REGION-2>- <YOUR-AWS-REGION-3>cloudWatch:clusterLogging: {}iam:vpcResourceControllerPolicy: truewithOIDC: truekind: ClusterConfigkubernetesNetworkConfig:ipFamily: IPv4managedNodeGroups:- amiFamily: AmazonLinux2desiredCapacity: 7disableIMDSv1: truedisablePodIMDS: falseiam:withAddonPolicies:albIngress: trueappMesh: falseappMeshPreview: falseautoScaler: trueawsLoadBalancerController: truecertManager: falsecloudWatch: falseebs: trueefs: falseexternalDNS: falsefsx: falseimageBuilder: falsexRay: falseinstanceSelector: {}instanceType: t3.2xlarge # Update to an instance type suitable for your workload and budgetlabels:alpha.eksctl.io/cluster-name: <CLUSTER-NAME> # Ensure this matches the name of your EKS clusteralpha.eksctl.io/nodegroup-name: standard-workersmaxSize: 9minSize: 4name: standard-workersprivateNetworking: falsereleaseVersion: ""securityGroups:withLocal: nullwithShared: nullssh:allow: falsepublicKeyPath: ""tags:alpha.eksctl.io/nodegroup-name: standard-workersalpha.eksctl.io/nodegroup-type: managedvolumeIOPS: 3000volumeSize: 80volumeThroughput: 125volumeType: gp3metadata:name: <TAGS> # Set a unique name for the resource group or tagging identifierregion: <YOUR-AWS-REGION> # Specify the AWS region where the cluster will be provisionedtags:cluster: <CLUSTER-NAME>owner: <YOUR-NAME>purpose: <CLUSTER-PURPOSE> # Purpose of the cluster (e.g., dev, test, production)scope: <USAGE-OF-CLUSTER> # Scope or boundary of usage (e.g., team-specific, project-specific)version: "1.31" # This is the latest Kubernetes version currently supported by Harness SMPprivateCluster:enabled: falseskipEndpointCreation: falsevpc:autoAllocateIPv6: falsecidr: <YOUR-CIDR> # for example, 192.168.0.0/16clusterEndpoints:privateAccess: falsepublicAccess: truemanageSharedNodeSecurityGroupRules: truenat:gateway: Single
-
-
Run the following command to create the EKS cluster using the YAML configuration:
eksctl create cluster -f <create-smp-cluster.yaml>infoThis command will trigger the provisioning of the entire infrastructure defined in the YAML — including the EKS control plane, node groups, VPC, IAM, and networking.
Replace
<create-smp-cluster.yaml>with the actual filename if you named it differently.On success, it outputs a final message like:
[✓] EKS cluster "<CLUSTER-NAME>" in "<YOUR-AWS-REGION>" region is ready[✓] Saved kubeconfig as "~/.kube/config"
Step 3: Verify the Cluster Deployment
After provisioning completes, verify the cluster was created successfully using the following commands:
-
Check the cluster status:
eksctl get cluster --region <YOUR-AWS-REGION> -
Confirm the nodes are ready:
kubectl get nodesYou should see all worker nodes in a
Readystate, as shown in example below:NAME STATUS ROLES AGE VERSIONip-192-168-20-26.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151aip-192-168-22-217.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151aip-192-168-28-24.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151aip-192-168-40-97.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151aip-192-168-52-54.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151aip-192-168-71-199.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151aip-192-168-80-135.us-east-2.compute.internal Ready <none> 16d v1.31.7-eks-473151a -
Confirm the Kubernetes context is set:
kubectl config current-contextThis should return the context of your newly created EKS cluster as shown below:
<USER>@email-domain.xyz@<CLUSTER-NAME>.<REGION>.eksctl.ioIf AWS config is not set, run the following command
aws eks --region=<YOUR-AWS-REGION> update-kubeconfig --cluster=<YOUR-CLUSTER-NAME>If any nodes are in a
NotReadystate or the context is incorrect, ensure yourkubectlis configured correctly and your IAM user has the necessary permissions.
Step 4: Configure the Amazon EBS CSI Driver
eksctl currently does not offer a built-in mechanism to automatically install the Amazon EBS CSI driver, which is required for provisioning Persistent Volumes (PVs) on your cluster.
To enable dynamic volume provisioning, you need to manually install and configure the EBS CSI driver using the steps below.
-
Create a namespace for your deployment.
kubectl create ns <HARNESS-NAMESPACE> -
Create an IAM role with a trust policy that allows Amazon EKS to assume the role via IAM Roles for Service Accounts (IRSA).
Get the OIDC Issuer URL for IRSA Configurationaws eks describe-cluster --name <AWS_CLUSTER_NAME> --region <YOUR-AWS-REGION> --query "cluster.identity.oidc.issuer" --output textExample output:
https://oidc.eks.us-east-1.amazonaws.com/id/EXAMPLEDOCIDUse the portion after
https://(i.e.,oidc.eks.us-east-1.amazonaws.com/id/EXAMPLEDOCID) as the<OIDC_PROVIDER>in thetrust-policy.jsonfile.Begin by creating a
trust-policy.jsonfile with the following content:{"Version": "2012-10-17","Statement": [{"Effect": "Allow","Principal": {"Federated": "arn:aws:iam::<AWS-ACCOUNT-ID>:oidc-provider/<OIDC-PROVIDER>"},"Action": "sts:AssumeRoleWithWebIdentity","Condition": {"StringEquals": {"<OIDC_PROVIDER>:sub": "system:serviceaccount:kube-system:ebs-csi-controller-sa"}}}]}Once the
trust-policy.jsonfile is created, use the following command to create the IAM role:aws iam create-role \--role-name AmazonEKS_EBS_CSI_DriverRole \--assume-role-policy-document file://trust-policy.json --region <YOUR-AWS-REGION> -
Attach the
AmazonEBSCSIDriverPolicyto the IAM role:aws iam attach-role-policy \--role-name AmazonEKS_EBS_CSI_DriverRole \--policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy --region <YOUR-AWS-REGION> -
Use the following script to verify that your infrastructure components are functioning correctly and ensure that your Kubernetes cluster is ready to deploy Harness Self-Managed Platform (SMP):
Health Check Script to verify you installation and upgrade
#!/bin/bashset -eecho "Starting Kubernetes Cluster Health Check"echo "----------------------------------------"# Generate a unique ID for this runRUN_ID=$(date +%s)TEST_NAMESPACE="health-check-${RUN_ID}"TEST_PVC="test-pvc-${RUN_ID}"TEST_POD="test-pod-${RUN_ID}"# Colors for outputGREEN='\033[0;32m'YELLOW='\033[1;33m'RED='\033[0;31m'NC='\033[0m' # No Color# Function to clean up resourcescleanup() {echo -e "${YELLOW}Cleaning up test resources...${NC}"kubectl delete pod $TEST_POD --namespace=$TEST_NAMESPACE --ignore-not-found=truekubectl delete pvc $TEST_PVC --namespace=$TEST_NAMESPACE --ignore-not-found=truekubectl delete namespace $TEST_NAMESPACE --ignore-not-found=trueecho -e "${GREEN}Cleanup completed${NC}"}# Function to print success messagesuccess() {echo -e "${GREEN}✅ $1${NC}"}# Function to print error message and exitfail() {echo -e "${RED}❌ $1${NC}"exit 1}# Function to print warning messagewarn() {echo -e "${YELLOW}⚠️ $1${NC}"}# Check if kubectl is installedif ! command -v kubectl &> /dev/null; thenfail "kubectl is not installed. Please install kubectl and configure it to connect to your cluster."fi# Check if kubectl can connect to the clusterif ! kubectl cluster-info &> /dev/null; thenfail "Cannot connect to Kubernetes cluster. Please check your kubeconfig file."fi# Trap for clean exittrap cleanup EXIT# Check 1: Create a test namespaceecho "Check 1: Creating test namespace $TEST_NAMESPACE"if kubectl create namespace $TEST_NAMESPACE &> /dev/null; thensuccess "Namespace created successfully"elsefail "Failed to create namespace $TEST_NAMESPACE"fi# Check 2: List available StorageClassesecho "Check 2: Checking available StorageClasses"SC_COUNT=$(kubectl get storageclass -o name | wc -l)if [ "$SC_COUNT" -eq 0 ]; thenfail "No StorageClasses found in the cluster"fiDEFAULT_SC=$(kubectl get storageclass -o=jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}')if [ -z "$DEFAULT_SC" ]; thenwarn "No default StorageClass found, will use the first available one"DEFAULT_SC=$(kubectl get storageclass -o=jsonpath='{.items[0].metadata.name}')fisuccess "Using StorageClass: $DEFAULT_SC"# Check 3: Create a PVC and pod together (handles WaitForFirstConsumer binding mode)echo "Check 3: Creating test PVC using StorageClass $DEFAULT_SC"cat <<EOF | kubectl apply -f - &> /dev/nullapiVersion: v1kind: PersistentVolumeClaimmetadata:name: $TEST_PVCnamespace: $TEST_NAMESPACEspec:accessModes:- ReadWriteOnceresources:requests:storage: 1GistorageClassName: $DEFAULT_SCEOFif [ $? -ne 0 ]; thenfail "Failed to create PVC"fi# Check 4: Immediately create a pod that uses the PVC (for WaitForFirstConsumer binding mode)echo "Check 4: Creating test pod that mounts the PVC"cat <<EOF | kubectl apply -f - &> /dev/nullapiVersion: v1kind: Podmetadata:name: $TEST_PODnamespace: $TEST_NAMESPACEspec:containers:- name: busyboximage: busybox:1.34command: ["sh", "-c", "echo 'Kubernetes storage test' > /data/test.txt && sleep 30"]volumeMounts:- name: test-volumemountPath: /datavolumes:- name: test-volumepersistentVolumeClaim:claimName: $TEST_PVCrestartPolicy: NeverEOFif [ $? -ne 0 ]; thenfail "Failed to create pod"fi# Wait for both pod to be running and PVC to be boundecho "Waiting for pod to be running and PVC to be bound (up to 2 minutes)..."TIMEOUT=120for i in $(seq 1 $TIMEOUT); doPOD_STATUS=$(kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o=jsonpath='{.status.phase}')PVC_STATUS=$(kubectl get pvc $TEST_PVC -n $TEST_NAMESPACE -o=jsonpath='{.status.phase}')if [ "$PVC_STATUS" == "Bound" ] && ([ "$POD_STATUS" == "Running" ] || [ "$POD_STATUS" == "Succeeded" ]); thensuccess "PVC successfully bound and pod is running"breakfiif [ $i -eq $TIMEOUT ]; thenecho "Timed out waiting. PVC status: $PVC_STATUS, Pod status: $POD_STATUS"kubectl get pvc $TEST_PVC -n $TEST_NAMESPACE -o yamlkubectl get pod $TEST_POD -n $TEST_NAMESPACE -o yamlkubectl get events -n $TEST_NAMESPACEfail "Resource creation timeout"fisleep 1# Show a spinner to indicate progressprintf "\r[%s]" "$(printf '=%.0s' $(seq 1 $i))"doneecho ""# Wait for pod completionecho "Waiting for pod to complete..."TIMEOUT=60for i in $(seq 1 $TIMEOUT); doPOD_STATUS=$(kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o=jsonpath='{.status.phase}' 2>/dev/null)# Check for completion (either running or succeeded is good)if [ "$POD_STATUS" == "Succeeded" ]; thensuccess "Pod completed successfully"breakfi# For running pods, check if they're actually readyif [ "$POD_STATUS" == "Running" ]; thenCONTAINER_READY=$(kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o=jsonpath='{.status.containerStatuses[0].ready}')if [ "$CONTAINER_READY" == "true" ]; thensuccess "Pod is running with container ready"breakfifi# Check for failure statesif [ "$POD_STATUS" == "Failed" ]; thenecho "Pod failed to run"kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o yamlkubectl get events -n $TEST_NAMESPACEfail "Pod execution failed"fi# Timeout checkif [ $i -eq $TIMEOUT ]; thenecho "Timed out waiting for pod to complete. Current status: $POD_STATUS"kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o yamlkubectl get events -n $TEST_NAMESPACEfail "Pod execution timeout"fisleep 1# Show a spinner to indicate progressprintf "\r[%s]" "$(printf '=%.0s' $(seq 1 $i))"doneecho ""# Wait for pod to completeecho "Waiting for pod to complete..."kubectl wait --for=condition=Ready pod/$TEST_POD -n $TEST_NAMESPACE --timeout=60s &> /dev/null || truePOD_STATUS=$(kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o=jsonpath='{.status.phase}')if [ "$POD_STATUS" == "Running" ] || [ "$POD_STATUS" == "Succeeded" ]; thensuccess "Pod completed successfully"elseecho "Pod did not complete successfully. Status: $POD_STATUS"kubectl get pod $TEST_POD -n $TEST_NAMESPACE -o yamlkubectl get events -n $TEST_NAMESPACEfail "Pod execution failed"fi# Optional: Add additional checks here# DNS checkecho "Check 5: Testing DNS resolution within the cluster"cat <<EOF | kubectl apply -f - &> /dev/nullapiVersion: v1kind: Podmetadata:name: dns-test-podnamespace: $TEST_NAMESPACEspec:containers:- name: dns-testimage: busybox:1.34command:- "sh"- "-c"- "nslookup kubernetes.default.svc.cluster.local > /dev/null && echo 'DNS test passed' || echo 'DNS test failed'"restartPolicy: NeverEOF# Wait for DNS test to completekubectl wait --for=condition=Ready pod/dns-test-pod -n $TEST_NAMESPACE --timeout=60s &> /dev/null || trueDNS_TEST_RESULT=$(kubectl logs dns-test-pod -n $TEST_NAMESPACE)if [[ "$DNS_TEST_RESULT" == *"DNS test passed"* ]]; thensuccess "DNS resolution is working correctly"elsewarn "DNS resolution may have issues. Check cluster DNS service."kubectl logs dns-test-pod -n $TEST_NAMESPACEfikubectl delete pod dns-test-pod -n $TEST_NAMESPACE --ignore-not-found=true &> /dev/nullecho ""echo -e "${GREEN}All health checks passed! ✅${NC}"echo -e "${GREEN}Kubernetes cluster is healthy and ready for workloads.${NC}"# Summary reportecho ""echo "Health Check Summary:"echo "---------------------"echo "Namespace creation: ✅"echo "StorageClass availability: ✅"echo "PVC provisioning: ✅"echo "Pod scheduling with volume: ✅"echo "DNS resolution: ✅"echo ""echo "To run this health check again, execute:"echo "$ bash $(basename "$0")"💡 The script checks for Kubernetes connectivity, StorageClass availability, PVC provisioning, pod scheduling, and DNS resolution.
Save the script as
k8s-health-check.sh, make it executable using:chmod +x k8s-health-check.shThen run it with:
./k8s-health-check.shIf all checks pass, your cluster is healthy and ready for workloads. ✅
Step 5: Install Self-Managed Platform in Amazon EKS
If you are using Kubernetes 1.3x, make sure to specify the storage class in your override file as mentioned in supported Kubernetes versions.
-
Download the latest Helm chart from the Harness GitHub Releases page.
- In the Assets section, locate and download the
harness-<release-version>.tgz(e.g., harness-0.29.0.tgz) file. - Extract the downloaded file and navigate to the extracted directory.
- In the Assets section, locate and download the
-
Create a file named
override-new.yamland add the following YAML content to it.global:# Required for Kubernetes v1.30 or above:# Explicitly define the StorageClass to ensure PVCs bind correctly.# "gp2" is a default AWS EBS-backed StorageClass in most EKS clusters.# You can also use other supported types like "gp3", depending on your storage performance and cost needs.storageClass: "gp2"storageClassName: "gp2"ingress:enabled: "true"hosts: ""tls:enabled: falsedefaultbackend:create: true # Deploys a default backend component in the cluster when set to trueloadbalancerURL: "" -
Install the Helm chart using the following command.
helm install <RELEASE-NAME> <PATH-TO-EXTRACTED-FOLDER> -f override-new.yaml -n <HARNESS-NAMESPACE> -
Verify that all PersistentVolumeClaims (PVCs) have been successfully created and are bound to their respective volumes in your namespace:
kubectl get pvc -n <HARNESS-NAMESPACE>Replace
<HARNESS-NAMESPACE>with the namespace where your workloads are deployed.if the PVCs are attached properly, their status will appear as
Bound, as shown below. If the status remainsPending, proceed to step 5 to manually attach the PVCs.NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGEdata-postgres-0 Bound pvc-328b51ff-0e4e-4594-8aa3-0334d5a61ada 8Gi RWO gp2 <unset> 22mdata-redis-sentinel-harness-server-0 Bound pvc-80b28b73-ecaf-47ff-81e5-4ba1071fc056 10Gi RWO gp2 <unset> 22mdata-redis-sentinel-harness-server-1 Pending <unset> 62sdatadir-mongodb-replicaset-chart-0 Bound pvc-09e78d03-8007-409e-8e60-76fcfa4594c9 20Gi RWO gp2 <unset> 22mdatadir-mongodb-replicaset-chart-1 Pending <unset> 47sminio Bound pvc-d68cbb06-bb84-4ffd-ba83-35b7a9387137 10Gi RWO gp2 <unset> 22mstorage-volume-harness-awsnlb-timescaledb-0 Bound pvc-3a8f10a9-e651-415a-8688-f64720ec1917 100Gi RWO gp2 <unset> 22mtimescaledb-backup-minio Bound pvc-f8351e00-7466-4319-87f6-0083a6e5fe01 200Gi RWO gp2 <unset> 22mwal-volume-harness-awsnlb-timescaledb-0 Bound pvc-72de96b7-3fd8-4c23-ae26-c9cd3afdab15 1Gi RWO gp2 <unset> 22m -
Attach the PersistentVolumeClaims (PVCs) by patching each one with the gp2 StorageClass. While you can use other available StorageClasses (such as gp3), this installation uses gp2 by default.
Use the following command to apply the patch in your Harness namespace.
kubectl get pvc -n <HARNESS-NAMESPACE> -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' | \while read pvc; doecho "Patching $pvc with gp2..."kubectl patch pvc "$pvc" -n <HARNESS-NAMESPACE> --type='merge' -p '{"spec":{"storageClassName":"gp2"}}'doneThis command will attach the PVCs. Once completed, you can verify the attachment by repeating step 4 above.
AWS EKS can create and attach Elastic Load Balancers as a Kubernetes Resource. For more information, go to Application load balancing on Amazon EKS in the EKS documentation.
-
Create a Load Balancer by saving the following configuration to a file named
loadbalancer.yaml, and then apply it to your cluster.---# Source: networking/templates/nginx/controller.yamlapiVersion: v1kind: ServiceAccountmetadata:name: harness-serviceaccountnamespace: harness---# Source: networking/templates/nginx/controller.yamlapiVersion: v1kind: ConfigMapmetadata:name: harness-ingress-controllernamespace: harnesslabels:data:proxy-body-size: 1024mproxy-read-timeout: "600"proxy-send-timeout: "600"---# Source: networking/templates/nginx/controller.yamlapiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata:name: harness-rolenamespace: harnessrules:- apiGroups:- ""resources:- namespacesverbs:- get- apiGroups:- ""resources:- configmaps- pods- secrets- endpointsverbs:- update- get- list- watch- apiGroups:- ""resources:- servicesverbs:- get- list- update- watch- apiGroups:- extensions- networking.k8s.ioresources:- ingressesverbs:- get- list- watch- apiGroups:- extensions- networking.k8s.ioresources:- ingresses/statusverbs:- update- apiGroups:- ""resourceNames:- ingress-controller-leader-harnessresources:- configmapsverbs:- get- update- apiGroups:- ""resources:- configmapsverbs:- create- apiGroups:- ""resources:- endpointsverbs:- create- get- update- apiGroups:- ""resources:- eventsverbs:- create- patch---# Source: networking/templates/nginx/controller.yamlapiVersion: rbac.authorization.k8s.io/v1kind: RoleBindingmetadata:name: harness-role-hsa-bindingnamespace: harnessroleRef:apiGroup: rbac.authorization.k8s.iokind: Rolename: harness-rolesubjects:- kind: ServiceAccountname: harness-serviceaccountnamespace: harness---# Source: networking/templates/nginx/controller.yamlapiVersion: v1kind: Servicemetadata:name: harness-ingress-controllernamespace: harnesslabels:annotations:spec:selector:app: harness-ingress-controllertype: 'LoadBalancer'# externalTrafficPolicy: 'Cluster'ports:- name: healthprotocol: TCPport: 10254targetPort: 10254- name: httpport: 80protocol: TCPtargetPort: http- name: httpsport: 443protocol: TCPtargetPort: https---# Source: networking/templates/nginx/default-backend.yamlapiVersion: v1kind: Servicemetadata:name: default-backendnamespace: harnesslabels:spec:ports:- name: httpport: 80protocol: TCPtargetPort: 8080selector:app: default-backendtype: ClusterIP---# Source: networking/templates/nginx/controller.yamlkind: DeploymentapiVersion: apps/v1metadata:name: harness-ingress-controllernamespace: harnesslabels:spec:replicas: 1selector:matchLabels:app: harness-ingress-controllerprogressDeadlineSeconds: 300strategy:rollingUpdate:maxSurge: 1maxUnavailable: 1type: RollingUpdatetemplate:metadata:labels:app: "harness-ingress-controller"spec:affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchLabels:app: "harness-ingress-controller"topologyKey: kubernetes.io/hostnameserviceAccountName: harness-serviceaccountterminationGracePeriodSeconds: 60securityContext:runAsUser: 101containers:- image: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v1.0.0-alpha.2name: nginx-ingress-controllerimagePullPolicy: IfNotPresentenvFrom:- configMapRef:name: harness-ingress-controllerresources:limits:memory: 512Mirequests:cpu: "0.5"memory: 512Miports:- name: httpcontainerPort: 8080protocol: TCP- name: httpscontainerPort: 8443protocol: TCPlivenessProbe:httpGet:path: /healthzport: 10254scheme: HTTPinitialDelaySeconds: 30timeoutSeconds: 5securityContext:allowPrivilegeEscalation: falseenv:- name: POD_NAMEvalueFrom:fieldRef:apiVersion: v1fieldPath: metadata.name- name: POD_NAMESPACEvalueFrom:fieldRef:apiVersion: v1fieldPath: metadata.namespaceargs:- /nginx-ingress-controller- --ingress-class=harness- --default-backend-service=$(POD_NAMESPACE)/default-backend- --election-id=ingress-controller-leader- --watch-namespace=$(POD_NAMESPACE)- --update-status=true- --configmap=$(POD_NAMESPACE)/harness-ingress-controller- --http-port=8080- --https-port=8443- --default-ssl-certificate=$(POD_NAMESPACE)/harness-cert- --publish-service=$(POD_NAMESPACE)/harness-ingress-controller---# Source: networking/templates/nginx/default-backend.yamlkind: DeploymentapiVersion: apps/v1metadata:name: default-backendnamespace: harnesslabels:spec:replicas: 1selector:matchLabels:app: default-backendtemplate:metadata:labels:app: default-backendspec:serviceAccountName: harness-serviceaccountterminationGracePeriodSeconds: 60containers:- name: default-http-backendimage: registry.k8s.io/defaultbackend-amd64:1.5imagePullPolicy: IfNotPresentlivenessProbe:httpGet:path: /healthzport: 8080scheme: HTTPinitialDelaySeconds: 30timeoutSeconds: 5resources:limits:memory: 20Mirequests:cpu: 10mmemory: 20MisecurityContext:runAsUser: 65534ports:- name: httpcontainerPort: 8080protocol: TCPAfter saving the file, run the following command to create the Load Balancer in your cluster.
kubectl create -f loadbalancer.yaml -n <HARNESS-NAMESPACE> -
Get the ELB URL by verifying that the LoadBalancer is provisioned and has an external IP using the command below:
kubectl get svc harness-ingress-controller -n <HARNESS-NAMESPACE>Make a note of the
EXTERNAL-IPfor theharness-ingress-controller. It should look like<STRING>.<YOUR-AWS-REGION>.elb.amazonaws.com.NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEharness-ingress-controller LoadBalancer 10.100.130.107 af5b132b743fb4XXXXXXX24581119f1b-1454307465.us-east-2.elb.amazonaws.com 10254:32709/TCP,80:32662/TCP,443:32419/TCP 38s -
Update the
override-new.yamlfile by adding theloadbalancerURLandhostsfields as shown below:global:loadbalancerURL: "http://<YOUR_ELB_ADDRESS>"ingress:hosts: "<YOUR_ELB_ADDRESS>"enabled: "true" -
Upgrade the Helm deployment, applying your new ELB as the load balancer to your configuration.
helm upgrade <RELEASE-NAME> <PATH-TO-EXTRACTED-FOLDER> -f override-new.yaml -n <HARNESS-NAMESPACE> -
Once all components are healthy, you can access SMP by navigating to the sign-up UI at
https://<YOUR_ELB_ADDRESS>/auth/#/signupto create your admin user. -
Complete to the post-install next steps.
Post-install next steps
- Deploy the Harness modules you want to use. For more information, go to Deploy Harness modules.
- Add your Harness license. For more information, go to Add a Harness license.
- Configure SMTP to allow for additional user invitations. For more information, go to Add SMTP configuration.