convoy docs
Search

Deploy to a remote cluster

Connect convoy to a second cluster with a kubeconfig Secret, and deploy a Release to it.

This guide connects convoy to a remote cluster in agentless mode. In this mode, convoy connects from the cluster where it runs to the API server of the remote cluster. It installs nothing on the remote cluster. The credentials come from a kubeconfig in a Secret. Then the guide deploys podinfo manifests from Git to the remote cluster.

Before you start#

  • convoy runs in the management cluster.
  • kubectl and the kubectl convoy plugin are on your PATH.
  • You can create convoy objects and Secrets in the default namespace of the management cluster. All examples use this namespace.
  • You have a kubeconfig file for the remote cluster. This guide calls it managed.kubeconfig.

Steps#

1. Prepare the kubeconfig#

  1. Make sure that the current context of managed.kubeconfig points to the remote cluster.
  2. Make sure that the kubeconfig contains the credentials and the CA data. It must not refer to local files.
  3. Make sure that the convoy pods can reach the server address in the kubeconfig.

convoy uses only the current context of the kubeconfig. The kubeconfig sets the server, the CA and the credentials. convoy does not use spec.agentless.server to connect.

A server address such as 127.0.0.1 works only from your workstation. The convoy controller-manager and the observer connect from their pods.

The identity in the kubeconfig needs write permissions for all objects that the Release applies. The target cluster authorizes the pre-apply dry run as a real write. See Security.

2. Create the kubeconfig Secret#

  1. Create the Secret in the namespace of the Cluster:

    sh
    kubectl create secret generic convoy-managed-kubeconfig -n default --from-file=kubeconfig=managed.kubeconfig

convoy reads the Secret from the namespace of the Cluster. The Secret key must match spec.agentless.auth.kubeconfig.secretRef.key. In this guide, the key is kubeconfig.

3. Create the Cluster#

  1. Save this manifest as cluster-auth-agentless.yaml:

    clusters/cluster-auth-agentless.yaml
    apiVersion: core.convoy.kumodo.io/v1alpha1
       kind: Cluster
       metadata:
         name: convoy-managed
         namespace: default
       spec:
         connectionMode: agentless
         agentless:
           server: https://convoy-managed-control-plane:6443
           auth:
             type: kubeconfig
             kubeconfig:
               secretRef:
                 name: convoy-managed-kubeconfig
                 key: kubeconfig
         metadata:
           type: kind
           role: managed
       
  2. Change spec.agentless.server to the server address of the remote cluster.

  3. Apply the manifest:

    sh
    kubectl apply -f cluster-auth-agentless.yaml
  4. Wait until the Cluster is ready:

    sh
    kubectl wait --for=condition=Ready clusters.core.convoy.kumodo.io/convoy-managed -n default --timeout=2m

kubeconfig is the only auth type for agentless mode. The types token, clientCert, execPlugin and oidc give Ready=False with reason Unsupported.

convoy copies spec.agentless.server into status.lastAttempted.resolvedCluster of each Release. Set it to the real address, so that the Release status shows the correct target.

4. Check the Cluster#

  1. Show the Cluster:

    sh
    kubectl get clusters.core.convoy.kumodo.io -n default

    The header line is NAME MODE REACHABLE VERSION AGE. For convoy-managed, make sure that REACHABLE is true.

  2. If the Cluster is not ready, read the reason of the Ready condition:

    sh
    kubectl describe clusters.core.convoy.kumodo.io convoy-managed -n default

Ready · written by convoy-controller-manager

ReasonStatusMeaning
ReachableTrueconvoy connected to the cluster and read its Kubernetes version.
UnsupportedFalseThe connection mode or the auth type is not implemented. Only inCluster, and agentless with kubeconfig auth, are implemented. convoy does not retry with backoff. The periodic resync checks the Cluster again.
ProbeFailedFalseconvoy could not connect to the cluster or read its version. convoy retries.

The cluster controller probes the API server with the discovery API. A missing Secret, a missing key or a bad kubeconfig gives reason ProbeFailed.

5. Create the source and the Release#

  1. Save this manifest as gitrepository-podinfo.yaml:

    sources/gitrepository-podinfo.yaml
    apiVersion: source.convoy.kumodo.io/v1alpha1
       kind: GitRepository
       metadata:
         name: podinfo
         namespace: default
       spec:
         auth:
           type: none
         interval: 1m0s
         minSyncInterval: 30s
         tls:
           insecureSkipVerify: true
         url: https://github.com/stefanprodan/podinfo.git
       
  2. Save this manifest as release-gitrepository-manifests-agentless.yaml:

    releases/release-gitrepository-manifests-agentless.yaml
    apiVersion: core.convoy.kumodo.io/v1alpha1
       kind: Release
       metadata:
         name: podinfo-managed
         namespace: default
       spec:
         clusterRef:
           name: convoy-managed
         source:
           type: gitRepository
           gitRepository:
             name: podinfo
             namespace: default
             ref:
               tag: 6.5.0
         content:
           type: manifests
           manifests:
             paths:
               - kustomize/deployment.yaml
               - kustomize/service.yaml
         syncPolicy:
           automatic: true
           prune:
             orphaned: false
             includeCRDs: false
             includeNamespaces: false
           interval: 1m
       
  3. Apply the two manifests:

    sh
    kubectl apply -f gitrepository-podinfo.yaml -f release-gitrepository-manifests-agentless.yaml
  4. Wait until convoy applies the render:

    sh
    kubectl wait --for=condition=Applied release/podinfo-managed -n default --timeout=5m

spec.clusterRef.name selects the Cluster. The Cluster must be in the namespace of the Release. The Release selects the Git tag 6.5.0 of podinfo.

While the Cluster is not reachable, the Release does not render and does not apply. The Applied reason is then ClusterNotReady, and convoy retries. A change to the Cluster does not start a reconcile of the Release. The Release reads the new Cluster state at its next reconcile.

The podinfo manifests have no metadata.namespace. convoy applies them to the default namespace of the remote cluster.

Check the result#

  1. Show the Release:

    sh
    kubectl get releases -n default

    The header line is NAME CONTENT SOURCE CLUSTER STATE APPLIED INSYNC HEALTHY LIFECYCLE AGE. For podinfo-managed, make sure that CLUSTER is convoy-managed and APPLIED is True.

  2. Show the health of each object:

    sh
    kubectl convoy release health podinfo-managed -n default
  3. Show the Deployment on the remote cluster:

    sh
    kubectl --kubeconfig managed.kubeconfig get deployment podinfo -n default

Clean up#

  1. Delete the Release:

    sh
    kubectl delete release podinfo-managed -n default
  2. Delete the source:

    sh
    kubectl delete -f gitrepository-podinfo.yaml
  3. Delete the Cluster:

    sh
    kubectl delete -f cluster-auth-agentless.yaml
  4. Delete the Secret:

    sh
    kubectl delete secret convoy-managed-kubeconfig -n default

Delete the Release before the Cluster and the Secret. The Release finalizer deletes the objects from the remote cluster. It needs a reachable Cluster for this. If the Cluster does not exist, the objects stay on the remote cluster. See Deletion.

Next steps#

In the code

convoy v0.9.0