Deploying Portainer CE in Kubernetes

Portainer is comprised of two elements, the Portainer Server, and the Portainer Agent. Both elements run as lightweight Docker containers on a Docker engine. There are many possible deployment scenarios, however, we have detailed the most common below. Please use the scenario that matches your configuration.

By default, Portainer will expose the UI over the port 9000 and expose a TCP tunnel server over the port 8000. The latter is optional and is only required if you plan to use the Edge compute features with Edge agents.

To see the requirements, please, visit the page of requirements.

Portainer Deployment


Pre-Req Note:

Portainer requires data persistence, and as a result needs at least one storage-class available to use. Portainer will attempt to use the "default" storage class during deployment. If you do NOT have a storage class tagged as "default" the deployment will likely fail.

You can check if you have a default storage class by running:

kubectl get sc

and looking for a storage class with (default) after its name:

defaultsc

kubectl patch storageclass <storage-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

and replace with the name of your storage class
Example: kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

Alternatively, if installing using our helm chart you can add the following option with helm install:

--set persistence.storageClass=<storage-class-name>



To deploy Portainer within a Kubernetes cluster, you can either use our HELM chart, or our provided manifests.

Portainer Server Deployment

Ensure you're using at least helm v3.2, which includes support for the --create-namespace argument.

First, add the Portainer helm repo running the following:

helm repo add portainer https://portainer.github.io/k8s/
helm repo update

Based on how you would like expose Portainer Service, Select an option below

Using the following command, Portainer will be available on port 30777.

helm install --create-namespace -n portainer portainer portainer/portainer

Using the following command, Poratainer service will be assigned a Cluster IP. You should use this with an Ingress, see Chart Configuration Options for Ingress related options.

helm install --create-namespace -n portainer portainer portainer/portainer \
--set service.type=ClusterIP
Example Deployment with Nginx Ingress
helm install --create-namespace -n portainer portainer portainer/portainer \
-- set service.type=ClusterIP \
-- set ingress.enabled=true \
-- set ingress.annotations='kubernetes.io/ingress.class: nginx' \
-- set ingress.hosts.host=portainer.example.io

Using the following command, Portainer will be available at an assigned LoadBalancer IP @ port 9000.

    helm install --create-namespace -n portainer portainer portainer/portainer \
--set service.type=LoadBalancer

Chart Configuration Options

The following table lists the configurable parameters of the Portainer chart and their default values. The values file can be found under deploy/helm/portainer/values.yaml.

The parameters will be keep updating.

Parameter Description Default
replicaCount Number of Portainer service replicas (ALWAYS set to 1) 1
image.repository Portainer Docker Hub repository portainer/portainer-ce
image.tag Tag for the Portainer image latest
image.pullPolicy Portainer image pulling policy IfNotPresent
imagePullSecrets If Portainer image requires to be in a private repository nil
nodeSelector Used to apply a nodeSelector to the deployment {}
serviceAccount.annotations Annotations to add to the service account null
serviceAccount.name The name of the service account to use portainer-sa-clusteradmin
service.type Service Type for the main Portainer Service; ClusterIP, NodePort and LoadBalancer LoadBalancer
service.httpPort HTTP port for accessing Portainer Web 9000
service.httpNodePort Static NodePort for accessing Portainer Web. Specify only if the type is NodePort 30777
service.edgePort TCP port for accessing Portainer Edge 8000
service.edgeNodePort Static NodePort for accessing Portainer Edge. Specify only if the type is NodePort 30776
service.annotations Annotations to add to the service {}
ingress.enabled Create an ingress for Portainer false
ingress.annotations Annotations to add to the ingress. For instane, kubernetes.io/ingress.class: nginx {}
ingress.hosts.host URL for Portainer Web. For instance, portainer.example.io nil
ingress.hosts.paths.path Path for the Portainer Web. /
ingress.hosts.paths.port Port for the Portainer Web. 9000
ingress.tls TLS support on ingress. Must create a secret with TLS certificates in advance []
resources Portainer resource requests and limits {}
persistence.enabled Whether to enable data persistence true
persistence.existingClaim Name of an existing PVC to use for data persistence nil
persistence.size Size of the PVC used for persistence 10Gi
persistence.annotations Annotations to apply to PVC used for persistence {}
persistence.storageClass StorageClass to apply to PVC used for persistence default
persistence.accessMode AccessMode for persistence ReadWriteOnce
persistence.selector Selector for persistence nil

Portainer Agent Only Deployment

Helm chart for Agent Only Deployments will be available soon. In the mean time please head over to YAML Manifests tab.

Portainer Server Deployment

Based on how you would like expose Portainer Service, Select an option below

Using the following command, Portainer will be available on port 30777.

kubectl apply -n portainer -f https://raw.githubusercontent.com/portainer/k8s/master/deploy/manifests/portainer/portainer.yaml

Using the following command, Portainer will be available at an assigned LoadBalancer IP @ port 9000.

kubectl apply -n portainer -f https://raw.githubusercontent.com/portainer/k8s/master/deploy/manifests/portainer/portainer-lb.yaml

Portainer Agent Only Deployment

Choose one of the tabs below based on how you would like to expose the agent.

Run the following command to deploy the Agent in your Kubernetes Cluster, agent will be available on port 30778.

kubectl apply -n portainer -f https://downloads.portainer.io/portainer-agent-k8s-nodeport.yaml

Run the following command to deploy the Agent in your Kubernetes Cluster, agent will be available on LoadBalancer assigned IP @ port 9001

kubectl apply -n portainer -f https://downloads.portainer.io/portainer-agent-k8s-lb.yaml

You can deploy Portainer in a Kubernetes environment in Windows using Docker Desktop.

Note

This scenario is for testing purpose only.

Enable Kubernetes in Docker Desktop

To enable Kubernetes in Docker Desktop, you need to open the dashboard of Docker Desktop. Right click the Docker icon in the system tray and click "dashboard"

dashboard

Click Settings:

settings

  1. Select Kubernetes 2. Select 'Enable Kubernetes' 3. Click 'Apply and Restart'.

kubernetes

After a few minutes, you will see that Kubernetes is running:

kubernetes_running

Portainer Server Deployment

Based on how you would like expose Portainer Service, Select an option below

Using the following command, Portainer will be available on port 30777.

kubectl apply -n portainer -f https://raw.githubusercontent.com/portainer/k8s/master/deploy/manifests/portainer/portainer.yaml

Using the following command, Portainer will be available at an assigned LoadBalancer IP @ port 9000.

kubectl apply -n portainer -f https://raw.githubusercontent.com/portainer/k8s/master/deploy/manifests/portainer/portainer-lb.yaml

Portainer Agent Only Deployment

Choose one of the tabs below based on how you would like to expose the agent.

Run the following command to deploy the Agent in your Kubernetes Cluster, agent will be available on port 30778.

kubectl apply -n portainer -f https://downloads.portainer.io/portainer-agent-k8s-nodeport.yaml

Run the following command to deploy the Agent in your Kubernetes Cluster, agent will be available on LoadBalancer assigned IP @ port 9001

kubectl apply -n portainer -f https://downloads.portainer.io/portainer-agent-k8s-lb.yaml

Regarding Persisting Data

The charts/manifests will create a persistent volume for storing Portainer data, using the default StorageClass.

In some Kubernetes clusters (microk8s), the default Storage Class simply creates hostPath volumes, which are not explicitly tied to a particular node. In a multi-node cluster, this can create an issue when the pod is terminated and rescheduled on a different node, "leaving" all the persistent data behind and starting the pod with an "empty" volume.

While this behaviour is inherently a limitation of using hostPath volumes, a suitable workaround is to use add a nodeSelector to the deployment, which effectively "pins" the portainer pod to a particular node.

The nodeSelector can be added in the following ways:

  1. Edit your own values.yaml and set the value of nodeSelector like this:

    nodeSelector: kubernetes.io/hostname: \<YOUR NODE NAME>
    
  2. Explicictly set the target node when deploying/updating the helm chart on the CLI, by including --set nodeSelector.kubernetes.io/hostname=<YOUR NODE NAME>

  3. If you've deployed Portainer via manifests, without Helm, run the following one-liner to "patch" the deployment, forcing the pod to always be scheduled on the node it's currently running on:

    kubectl patch deployments -n portainer portainer -p '{"spec": {"template": {"spec": {"nodeSelector": {"kubernetes.io/hostname": "'$(kubectl get pods -n portainer -o jsonpath='{ ..nodeName }')'"}}}}}' || (echo Failed to identify current node of portainer pod; exit 1)
    


Notes

Contribute to these docs