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.
kubectland the kubectl convoy plugin are on yourPATH.- You can create convoy objects and Secrets in the
defaultnamespace 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#
- Make sure that the current context of
managed.kubeconfigpoints to the remote cluster. - Make sure that the kubeconfig contains the credentials and the CA data. It must not refer to local files.
- 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#
Create the Secret in the namespace of the Cluster:
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#
Save this manifest as
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: managedChange
spec.agentless.serverto the server address of the remote cluster.Apply the manifest:
kubectl apply -f cluster-auth-agentless.yamlWait until the Cluster is ready:
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#
Show the Cluster:
kubectl get clusters.core.convoy.kumodo.io -n defaultThe header line is
NAME MODE REACHABLE VERSION AGE. Forconvoy-managed, make sure thatREACHABLEistrue.If the Cluster is not ready, read the reason of the
Readycondition:kubectl describe clusters.core.convoy.kumodo.io convoy-managed -n default
Ready · written by convoy-controller-manager
| Reason | Status | Meaning |
|---|---|---|
Reachable | True | convoy connected to the cluster and read its Kubernetes version. |
Unsupported | False | The 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. |
ProbeFailed | False | convoy 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#
Save this manifest as
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.gitSave this manifest as
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: 1mApply the two manifests:
kubectl apply -f gitrepository-podinfo.yaml -f release-gitrepository-manifests-agentless.yamlWait until convoy applies the render:
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#
Show the Release:
kubectl get releases -n defaultThe header line is
NAME CONTENT SOURCE CLUSTER STATE APPLIED INSYNC HEALTHY LIFECYCLE AGE. Forpodinfo-managed, make sure thatCLUSTERisconvoy-managedandAPPLIEDisTrue.Show the health of each object:
kubectl convoy release health podinfo-managed -n defaultShow the Deployment on the remote cluster:
kubectl --kubeconfig managed.kubeconfig get deployment podinfo -n default
Clean up#
Delete the Release:
kubectl delete release podinfo-managed -n defaultDelete the source:
kubectl delete -f gitrepository-podinfo.yamlDelete the Cluster:
kubectl delete -f cluster-auth-agentless.yamlDelete the Secret:
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
api/core.validateClusterAuthSpecapi/core/validation.go:92internal/auth.KubeconfigAuthenticator.RESTConfiginternal/auth/kubeconfig.go:37internal/clusterconn.(*Connector).Connectinternal/clusterconn/connector.go:64internal/controller/cluster.computeStatusinternal/controller/cluster/reconcile.go:45internal/controller/release.(*Controller).finalizeinternal/controller/release/controller.go:553