Portainer.io Part 1: Setup, CE and BE, Registries and K8s provisioning

Published: Jul 7, 2023 by Isaac Johnson

Portainer.io has long been on my list to check out. It is one of the leading container management apps for docker, though it can also be used to monitor Swarm, Kubernetes, ACI, Nomad or even spin up a new K8s (microk8s or a Cloud Provider).

Today we’ll setup and test Portainer CE and BE (with a free 3 node license). I just want to preface the rest by saying I clearly had some gripes about the limitations of the Community Edition and the endless push to upgrade to their commercial. However, about half way down I pivot to the free 1y 3 node environment license which really unlocks quite a lot.

I’ll be following up the last post and using the same Synology DS220+ NAS to host Portainer as I did the registry. However, you can run Portainer in Kubernetes just as easily.

Use Case

Now that we have a registry container running in docker, as described in the last post:

ijohnson@sirnasilot:~$ sudo docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED      STATUS      PORTS                                       NAMES
83af22fb4b32   registry:latest   "/entrypoint.sh /etc…"   3 days ago   Up 3 days>5000/tcp, :::5050->5000/tcp   registry-1

We may wish to monitor it. This is where portainer comes into play.

Portainer Installation

I’ll first need to create a volume for Portainer data

$ sudo docker volume create portainer_data

Next, I can download and run the Portainer-ce pod directly

ijohnson@sirnasilot:~$ sudo docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
Unable to find image 'portainer/portainer-ce:latest' locally
latest: Pulling from portainer/portainer-ce
772227786281: Pull complete
96fd13befc87: Pull complete
5171176db7f2: Pull complete
a143fdc4fa02: Pull complete
b622730c7bdc: Pull complete
c1cad9f5200f: Pull complete
d8a77b01f2cb: Pull complete
0d4d8543f764: Pull complete
c6fd0bcf10c9: Pull complete
889200668c1c: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:94c3056dbe879f3a3df06b427713392a0962924914f5c2fc557de3797f59f926
Status: Downloaded newer image for portainer/portainer-ce:latest

I can now see we are serving traffic on 8000, 9443 and 9000

ijohnson@sirnasilot:~$ sudo docker ps
CONTAINER ID   IMAGE                           COMMAND                  CREATED          STATUS          PORTS                                                                                            NAMES
42b68c9ce6a1   portainer/portainer-ce:latest   "/portainer"             25 seconds ago   Up 22 seconds>8000/tcp, :::8000->8000/tcp,>9443/tcp, :::9443->9443/tcp, 9000/tcp   portainer
83af22fb4b32   registry:latest                 "/entrypoint.sh /etc…"   3 days ago       Up 3 days>5000/tcp, :::5050->5000/tcp                                                        registry-1

I can now access the setup UI on 9443


I’ll create a user with a password which then brings me to the Quick Setup home page


Adding Registries

I’ll want to add both my NAS hosted registry and my Harbor one


Since the NAS registry exists within the network, I need no auth


My Harbor, however, requires auth


I can now see them added, but apparently the best features are behind the business edition. This is rather ugly. Too much harassment to upgrade for my taste


Even the logs are paywalled with giant ugly orange lockout screens. Seriously, this is terrible



Let’s look at images. We can see them in the “local” section


I was surprised I could see Volumes details without more Upgrade graphics


The host details confirm I did what is not officially allowed - I jammed an 8Gb SODIM in my new DS220+ and it’s running with 10Gb of RAM



We can add all, i mean, well some of the environment types, but Upgrade Now and we can do the rest.


I clicked Kubernetes then “Start Wizard”. They honestly locked the import of a kubeconfig as a “business feature”.


I’ll try node port as I know my k8s won’t do the LB

builder@DESKTOP-QADGF36:~$ kubectl apply -f https://downloads.portainer.io/ce2-18/portainer-agent-k8s-nodeport.yaml
namespace/portainer created
serviceaccount/portainer-sa-clusteradmin created
clusterrolebinding.rbac.authorization.k8s.io/portainer-crb-clusteradmin created
service/portainer-agent created
service/portainer-agent-headless created
deployment.apps/portainer-agent created

I’ll see what is serving 9001

builder@DESKTOP-QADGF36:~$ kubectl get svc --all-namespaces | grep portainer
portainer               portainer-agent                                            NodePort   <none>                                                 9001:30778/TCP                                                                                              50s
portainer               portainer-agent-headless                                   ClusterIP      None            <none>                                                 <none>                                                                                                      50s

That shows the NodPort as 30778

$ kubectl describe svc portainer-agent -n portainer
Name:                     portainer-agent
Namespace:                portainer
Labels:                   <none>
Annotations:              field.cattle.io/publicEndpoints: [{"port":30778,"protocol":"TCP","serviceName":"portainer:portainer-agent","allNodes":true}]
Selector:                 app=portainer-agent
Type:                     NodePort
IP Family Policy:         SingleStack
IP Families:              IPv4
Port:                     http  9001/TCP
TargetPort:               9001/TCP
NodePort:                 http  30778/TCP
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

I decided to use the Node that the pod lived on

$ kubectl describe pod portainer-agent-69b4d67ff-thrfm -n portainer
Name:         portainer-agent-69b4d67ff-thrfm
Namespace:    portainer
Priority:     0
Node:         builder-hp-elitebook-850-g2/
Start Time:   Thu, 06 Jul 2023 19:32:03 -0500
Labels:       app=portainer-agent
Annotations:  <none>
Status:       Running
... snip ...

So I used in the Portainer UI


I can now see my K8s stack there in the UI


We can see some of the objects there


I can view some of the details of Applications


For example, the Azure Vote App


Though, when I went to “edit” the application, I couldn’t see anything


I found services went out to lunch and never came back


Though, Ingresses worked which was more interesting


Volumes was handy as it showed some waste I have to cleanup


Cluster Details

We can view Cluster Health


I can pick a node and view some stats, which did as it suggested and refreshed every 30s, which was the min setting


I can view events on a node which is handy when troubleshooting problems


I can also pause and drain from the UI which is really useful for planned maintenance


And on Security Constraints we can… oh wait, yet another paywall



While I can add users


and teams


I can only use Admin and Standard as Roles, yes, you guessed it, got to upgrade for that


Take 3

Seems they have a promotion at the moment to signup and get 3 nodes for free.


You have to love radio buttons with only “yes” on contact


I did get a license key and a welcome email from my success liaison a minute later


We can now click the “Upgrade” link in the upper right, paste our key and get an error


Let me pull and push into my registry hosted on the NAS, maybe it will find it there

ijohnson@sirnasilot:~$ sudo docker pull portainer/portainer-ee:2.18.4
2.18.4: Pulling from portainer/portainer-ee
772227786281: Already exists
96fd13befc87: Already exists
5171176db7f2: Already exists
a143fdc4fa02: Already exists
b622730c7bdc: Already exists
c1cad9f5200f: Already exists
69ae32ddde08: Pull complete
4a0d116cdc71: Pull complete
08962690b30c: Pull complete
78e44cf728cd: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:656ca138b68f9aaafd0923ad85e89e84d0be7001faa6ff2c9155bbdab0527ae4
Status: Downloaded newer image for portainer/portainer-ee:2.18.4

ijohnson@sirnasilot:~$ sudo docker tag docker.io/portainer/portainer-ee:2.18.4 registry.freshbrewed.science:8443/portainer/portainer-ee:2.18.4

ijohnson@sirnasilot:~$ sudo docker push registry.freshbrewed.science:8443/portainer/portainer-ee:2.18.4
The push refers to repository [registry.freshbrewed.science:8443/portainer/portainer-ee]
5f70bf18a086: Pushed
5edb9da25c2d: Pushed
bc109744fe98: Pushed
538e17c76df3: Pushed
77a53a9a27d0: Pushed
c6713b0b1e7a: Pushed
b4960c616612: Pushed
1ee41f4fbd13: Pushed
df0cbd66321a: Pushed
4776464837fd: Pushed
8c004456aeb5: Pushed
2.18.4: digest: sha256:ae7e5a29fd2ec299f542f228ada65710980ae42cf100d87ce37ccb7c8e86ecc0 size: 2626

Still no go. Let’s kill this instance and try with EE

Portainer EE

First I have to kill the last

ijohnson@sirnasilot:~$ sudo docker ps
CONTAINER ID   IMAGE                           COMMAND                  CREATED          STATUS          PORTS                                                                                            NAMES
42b68c9ce6a1   portainer/portainer-ce:latest   "/portainer"             26 minutes ago   Up 26 minutes>8000/tcp, :::8000->8000/tcp,>9443/tcp, :::9443->9443/tcp, 9000/tcp   portainer
83af22fb4b32   registry:latest                 "/entrypoint.sh /etc…"   3 days ago       Up 3 days>5000/tcp, :::5050->5000/tcp                                                        registry-1

ijohnson@sirnasilot:~$ sudo docker stop 42b68c9ce6a1
ijohnson@sirnasilot:~$ sudo docker ps
CONTAINER ID   IMAGE             COMMAND                  CREATED      STATUS      PORTS                                       NAMES
83af22fb4b32   registry:latest   "/entrypoint.sh /etc…"   3 days ago   Up 3 days>5000/tcp, :::5050->5000/tcp   registry-1

Just to keep it simple, I’ll create a new volume for EE

ijohnson@sirnasilot:~$ sudo docker volume create portainer_data2

Now I can launch it

ijohnson@sirnasilot:~$ sudo docker run -d -p 8000:8000 -p 9443:9443 --name portaineree --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data2:/data portainer/portainer-ee:latest

ijohnson@sirnasilot:~$ sudo docker ps
CONTAINER ID   IMAGE                           COMMAND                  CREATED          STATUS          PORTS                                                                                            NAMES
5fa76248b69d   portainer/portainer-ee:latest   "/portainer"             23 seconds ago   Up 20 seconds>8000/tcp, :::8000->8000/tcp,>9443/tcp, :::9443->9443/tcp, 9000/tcp   portaineree
83af22fb4b32   registry:latest                 "/entrypoint.sh /etc…"   3 days ago       Up 3 days>5000/tcp, :::5050->5000/tcp                                                        registry-1

This time after I connect and add the Admin user, I have to add a License Key


I now see a “business edition”


I’ll add back my registries


And I see Browse now available


I worked with the UI to test the ports and IPs until I figured out the proper localnas endpoint.

I could then browse the contents:


That is a pretty powerful feature, in my opinion.

I can also see tags, sizes and even add a tag


As you can see, we can add tags and view things like Exposed ports

Now that I’m using the “EE” image, I can delete the old CE version


I initially got an error


A force warned it will be removed even if used by stopped containers


So I first removed the stopped container


which let me remove non-persistent volumes (nice!)


I can now see it is unused in the Images area


This time, removing worked just fine


I found the license will last me a year


Setting up a K8s

We can use Portainer to create new Kubernetes environments as well.


On Prem

The On-prem install will setup MicroK8s


After I create a credential, I can setup the AddOns, set a name and list the IPs to use


I can go to environments to see it is creating


Once done, I can view the details in the Kubernetes dashboard


I can see it indeed added the Registry service


As you might expect, I can also see Host details like CPU and Memory


Though even in BE mode, we can only select between 30s and 60s for stats


If I want to use this locally with Kubectl commands, I can go to environments


and click the “Kubeconfig” button


this downloads a YAML file we can use with kubeconfig

builder@DESKTOP-QADGF36:~/Workspaces$ kubectl get nodes --kubeconfig=/mnt/c/Users/isaac/Downloads/admin-t100.yaml
builder-t100   Ready    <none>   16m   v1.24.13-2+cd9733de84ad4b

I gave it some time, the Memory graph was fine, but the CPU one had a rather interesting Y axis


KaaS Provider

Let’s create a CIVO cluster first. Presently I have no Civo k8s


I’ll need to get my API key from settings


And use that for the Credentials section


I can now name it, set the node count, region, etc


Clicking Provision shows it’s now creating the cluster in CIVO


When done, I can see it listed in the Environments page


And back in CIVO, I can see the new cluster listed


To remove, I can just select the cluster and click remove


which will confirm


Though, as you would expect, this just removes it from Portainer, not from CIVO. The cluster is still live and running in the cloud


To save some money, I’ll click Delete from the CIVO K8s page


And a quick pro-tip for clouds like CIVO, Linode (Akamai) and DO - make sure to check Volumes as well as often PVCs do not auto-delete (and then you’ll get billed for object storage at the end of the month)



Clearly, they used to give 5 nodes for free but decided the roll that back to just 3.

Even the “Take 5” link really forwards to the Take 3 page


The pricing page does have a home and student edition for $150/year


I actually think their pricing is pretty fair. I’m quite tempted to pay for the Home edition because that just equates to about $12/mo and that is streaming-service pricing.


I think Portainer is pretty solid offering. Certianly, it covers a lot of ground from the Kubernetes observability and interaction to the local docker environments. I loved the Registry browsing and having the ability to spin up on-prem clusters with ease.

What I was less thrilled with was the endless “buy now” decorations. I get it - you want to sell me an upgrade. I do not fault a company for trying to flip a freebee to a premium. But I do take issue with locking essential features like access logs behind a paywall. Again, I’m not so annoyed as not to pay - I might very well pull the trigger on the Home Edition. But I really wish the entry level business offered more than 5 nodes for the $1000.

Clearly they had more in the past; we can see G2 pricing said it has a free 5-node business version same with Sourceforge


And the G2 page was updated as recently as Jan 17 2023 so the change happened in the last 6 months without any sort of announcement.


This just leads to a bit of a trust issue. If you reduce an offering without any kind of announcement, even the “Take 5” links go to a “Take 3”, then I have trust issues with the vendor.

But less us set aside pricing for a moment - the product is quite solid and worth looking into and I’ll likely keep this in my stack as it really solves a lot of problems. I just wish they would be more forthright with their pricing and plans.

Synology NAS Docker Registry Portainer

Have something to add? Feedback? Try our new forums

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes